public function execute(PhutilArgumentParser $args)
 {
     $console = PhutilConsole::getConsole();
     $public_keyfile = $args->getArg('public');
     if (!strlen($public_keyfile)) {
         throw new PhutilArgumentUsageException(pht('You must specify the path to a public keyfile with %s.', '--public'));
     }
     if (!Filesystem::pathExists($public_keyfile)) {
         throw new PhutilArgumentUsageException(pht('Specified public keyfile "%s" does not exist!', $public_keyfile));
     }
     $public_key = Filesystem::readFile($public_keyfile);
     $pkcs8_keyfile = $args->getArg('pkcs8');
     if (!strlen($pkcs8_keyfile)) {
         throw new PhutilArgumentUsageException(pht('You must specify the path to a pkcs8 keyfile with %s.', '--pkc8s'));
     }
     if (!Filesystem::pathExists($pkcs8_keyfile)) {
         throw new PhutilArgumentUsageException(pht('Specified pkcs8 keyfile "%s" does not exist!', $pkcs8_keyfile));
     }
     $pkcs8_key = Filesystem::readFile($pkcs8_keyfile);
     $warning = pht('Adding a PKCS8 keyfile to the cache can be very dangerous. If the ' . 'PKCS8 file really encodes a different public key than the one ' . 'specified, an attacker could use it to gain unauthorized access.' . "\n\n" . 'Generally, you should use this option only in a development ' . 'environment where ssh-keygen is broken and it is inconvenient to ' . 'fix it, and only if you are certain you understand the risks. You ' . 'should never cache a PKCS8 file you did not generate yourself.');
     $console->writeOut("%s\n", phutil_console_wrap($warning));
     $prompt = pht('Really trust this PKCS8 keyfile?');
     if (!phutil_console_confirm($prompt)) {
         throw new PhutilArgumentUsageException(pht('Aborted workflow.'));
     }
     $key = PhabricatorAuthSSHPublicKey::newFromRawKey($public_key);
     $key->forcePopulatePKCS8Cache($pkcs8_key);
     $console->writeOut("%s\n", pht('Cached PKCS8 key for public key.'));
     return 0;
 }
 public function didExecute(PhutilArgumentParser $args)
 {
     $console = PhutilConsole::getConsole();
     $patches = $this->getPatches();
     if (!$this->isDryRun() && !$this->isForce()) {
         $console->writeOut(phutil_console_wrap(pht('Before running storage upgrades, you should take down the ' . 'Phabricator web interface and stop any running Phabricator ' . 'daemons (you can disable this warning with %s).', '--force')));
         if (!phutil_console_confirm(pht('Are you ready to continue?'))) {
             $console->writeOut("%s\n", pht('Cancelled.'));
             return 1;
         }
     }
     $apply_only = $args->getArg('apply');
     if ($apply_only) {
         if (empty($patches[$apply_only])) {
             throw new PhutilArgumentUsageException(pht("%s argument '%s' is not a valid patch. " . "Use '%s' to show patch status.", '--apply', $apply_only, './bin/storage status'));
         }
     }
     $no_quickstart = $args->getArg('no-quickstart');
     $init_only = $args->getArg('init-only');
     $no_adjust = $args->getArg('no-adjust');
     $this->upgradeSchemata($apply_only, $no_quickstart, $init_only);
     if ($no_adjust || $init_only || $apply_only) {
         $console->writeOut("%s\n", pht('Declining to apply storage adjustments.'));
         return 0;
     } else {
         return $this->adjustSchemata(false);
     }
 }
 public function execute(PhutilArgumentParser $args)
 {
     $supported_types = id(new PhutilSymbolLoader())->setAncestorClass('PhabricatorTestDataGenerator')->loadObjects();
     echo "These are the types of data you can generate:\n";
     foreach (array_keys($supported_types) as $typetmp) {
         echo "\t" . $typetmp . "\n";
     }
     echo "\n";
     $prompt = 'Are you sure you want to generate lots of test data?';
     if (!phutil_console_confirm($prompt, $default_no = true)) {
         return;
     }
     $argv = $args->getArg('args');
     if (count($argv) == 0 || count($argv) == 1 && $argv[0] == 'all') {
         $this->infinitelyGenerate($supported_types);
     } else {
         $new_supported_types = array();
         for ($i = 0; $i < count($argv); $i++) {
             $arg = $argv[$i];
             if (array_key_exists($arg, $supported_types)) {
                 $new_supported_types[$arg] = $supported_types[$arg];
             } else {
                 echo "The type " . $arg . " is not supported by the lipsum generator.\n";
             }
         }
         $this->infinitelyGenerate($new_supported_types);
     }
     echo "None of the input types were supported.\n";
     echo "The supported types are:\n";
     echo implode("\n", array_keys($supported_types));
 }
 public function execute(PhutilArgumentParser $args)
 {
     $console = PhutilConsole::getConsole();
     $id = $args->getArg('id');
     if (!$id) {
         throw new PhutilArgumentUsageException(pht('Specify a public key to trust with --id.'));
     }
     $key = id(new PhabricatorAuthSSHKeyQuery())->setViewer($this->getViewer())->withIDs(array($id))->executeOne();
     if (!$key) {
         throw new PhutilArgumentUsageException(pht('No public key exists with ID "%s".', $id));
     }
     if ($key->getIsTrusted()) {
         throw new PhutilArgumentUsageException(pht('Public key with ID %s is already trusted.', $id));
     }
     if (!$key->getObject() instanceof AlmanacDevice) {
         throw new PhutilArgumentUsageException(pht('You can only trust keys associated with Almanac devices.'));
     }
     $handle = id(new PhabricatorHandleQuery())->setViewer($this->getViewer())->withPHIDs(array($key->getObject()->getPHID()))->executeOne();
     $console->writeOut("**<bg:red> %s </bg>**\n\n%s\n\n%s\n\n%s", pht('IMPORTANT!'), phutil_console_wrap(pht('Trusting a public key gives anyone holding the corresponding ' . 'private key complete, unrestricted access to all data in ' . 'Phabricator. The private key will be able to sign requests that ' . 'skip policy and security checks.')), phutil_console_wrap(pht('This is an advanced feature which should normally be used only ' . 'when building a Phabricator cluster. This feature is very ' . 'dangerous if misused.')), pht('This key is associated with device "%s".', $handle->getName()));
     $prompt = pht('Really trust this key?');
     if (!phutil_console_confirm($prompt)) {
         throw new PhutilArgumentUsageException(pht('User aborted workflow.'));
     }
     $key->setIsTrusted(1);
     $key->save();
     $console->writeOut("**<bg:green> %s </bg>** %s\n", pht('TRUSTED'), pht('Key %s has been marked as trusted.', $id));
 }
 public function execute(PhutilArgumentParser $args)
 {
     $is_dry = $args->getArg('dryrun');
     $is_force = $args->getArg('force');
     if (!$is_dry && !$is_force) {
         echo phutil_console_wrap("Are you completely sure you really want to permanently destroy all " . "storage for Phabricator data? This operation can not be undone and " . "your data will not be recoverable if you proceed.");
         if (!phutil_console_confirm('Permanently destroy all data?')) {
             echo "Cancelled.\n";
             exit(1);
         }
         if (!phutil_console_confirm('Really destroy all data forever?')) {
             echo "Cancelled.\n";
             exit(1);
         }
     }
     $api = $this->getAPI();
     $patches = $this->getPatches();
     $databases = $api->getDatabaseList($patches);
     $databases[] = $api->getDatabaseName('meta_data');
     foreach ($databases as $database) {
         if ($is_dry) {
             echo "DRYRUN: Would drop database '{$database}'.\n";
         } else {
             echo "Dropping database '{$database}'...\n";
             queryfx($api->getConn('meta_data', $select_database = false), 'DROP DATABASE IF EXISTS %T', $database);
         }
     }
     if (!$is_dry) {
         echo "Storage was destroyed.\n";
     }
     return 0;
 }
 public function handleMessage(PhutilConsoleMessage $message)
 {
     $data = $message->getData();
     $type = $message->getType();
     switch ($type) {
         case PhutilConsoleMessage::TYPE_CONFIRM:
             $ok = phutil_console_confirm($data['prompt'], !$data['default']);
             return $this->buildMessage(PhutilConsoleMessage::TYPE_INPUT, $ok);
         case PhutilConsoleMessage::TYPE_PROMPT:
             $response = phutil_console_prompt($data['prompt'], idx($data, 'history'));
             return $this->buildMessage(PhutilConsoleMessage::TYPE_INPUT, $response);
         case PhutilConsoleMessage::TYPE_OUT:
             $this->writeText(STDOUT, $data);
             return null;
         case PhutilConsoleMessage::TYPE_ERR:
             $this->writeText(STDERR, $data);
             return null;
         case PhutilConsoleMessage::TYPE_LOG:
             if ($this->enableLog) {
                 $this->writeText(STDERR, $data);
             }
             return null;
         default:
             if ($this->handler) {
                 return call_user_func($this->handler, $message);
             } else {
                 throw new Exception("Received unknown console message of type '{$type}'.");
             }
     }
 }
 public function execute(PhutilArgumentParser $args)
 {
     $console = PhutilConsole::getConsole();
     $supported_types = id(new PhutilClassMapQuery())->setAncestorClass('PhabricatorTestDataGenerator')->execute();
     $console->writeOut("%s:\n\t%s\n", pht('These are the types of data you can generate'), implode("\n\t", array_keys($supported_types)));
     $prompt = pht('Are you sure you want to generate lots of test data?');
     if (!phutil_console_confirm($prompt, true)) {
         return;
     }
     $argv = $args->getArg('args');
     if (count($argv) == 0 || count($argv) == 1 && $argv[0] == 'all') {
         $this->infinitelyGenerate($supported_types);
     } else {
         $new_supported_types = array();
         for ($i = 0; $i < count($argv); $i++) {
             $arg = $argv[$i];
             if (array_key_exists($arg, $supported_types)) {
                 $new_supported_types[$arg] = $supported_types[$arg];
             } else {
                 $console->writeErr("%s\n", pht('The type %s is not supported by the lipsum generator.', $arg));
             }
         }
         $this->infinitelyGenerate($new_supported_types);
     }
     $console->writeOut("%s\n%s:\n%s\n", pht('None of the input types were supported.'), pht('The supported types are'), implode("\n", array_keys($supported_types)));
 }
 public function execute(PhutilArgumentParser $args)
 {
     $console = PhutilConsole::getConsole();
     $repos = id(new PhabricatorRepositoryQuery())->setViewer($this->getViewer())->execute();
     if (!$repos) {
         $console->writeErr("%s\n", pht('There are no repositories.'));
         return 0;
     }
     $from = $args->getArg('from');
     if (!strlen($from)) {
         throw new Exception(pht('You must specify a path prefix to move from with --from.'));
     }
     $to = $args->getArg('to');
     if (!strlen($to)) {
         throw new Exception(pht('You must specify a path prefix to move to with --to.'));
     }
     $rows = array();
     $any_changes = false;
     foreach ($repos as $repo) {
         $src = $repo->getLocalPath();
         $row = array('repository' => $repo, 'move' => false, 'monogram' => $repo->getMonogram(), 'src' => $src, 'dst' => '');
         if (strncmp($src, $from, strlen($from))) {
             $row['action'] = pht('Ignore');
         } else {
             $dst = $to . substr($src, strlen($from));
             $row['action'] = phutil_console_format('**%s**', pht('Move'));
             $row['dst'] = $dst;
             $row['move'] = true;
             $any_changes = true;
         }
         $rows[] = $row;
     }
     $table = id(new PhutilConsoleTable())->addColumn('action', array('title' => pht('Action')))->addColumn('monogram', array('title' => pht('Repository')))->addColumn('src', array('title' => pht('Src')))->addColumn('dst', array('title' => pht('dst')))->setBorders(true);
     foreach ($rows as $row) {
         $display = array_select_keys($row, array('action', 'monogram', 'src', 'dst'));
         $table->addRow($display);
     }
     $table->draw();
     if (!$any_changes) {
         $console->writeOut(pht('No matching repositories.') . "\n");
         return 0;
     }
     $prompt = pht('Apply these changes?');
     if (!phutil_console_confirm($prompt)) {
         throw new Exception(pht('Declining to apply changes.'));
     }
     foreach ($rows as $row) {
         if (empty($row['move'])) {
             continue;
         }
         $repo = $row['repository'];
         $details = $repo->getDetails();
         $details['local-path'] = $row['dst'];
         queryfx($repo->establishConnection('w'), 'UPDATE %T SET details = %s WHERE id = %d', $repo->getTableName(), phutil_json_encode($details), $repo->getID());
     }
     $console->writeOut(pht('Applied changes.') . "\n");
     return 0;
 }
 public function execute(PhutilArgumentParser $args)
 {
     $console = PhutilConsole::getConsole();
     $viewer = $this->getViewer();
     $subscription_phid = $args->getArg('subscription');
     if (!$subscription_phid) {
         throw new PhutilArgumentUsageException(pht('Specify which subscription to invoice with %s.', '--subscription'));
     }
     $subscription = id(new PhortuneSubscriptionQuery())->setViewer($viewer)->withPHIDs(array($subscription_phid))->needTriggers(true)->executeOne();
     if (!$subscription) {
         throw new PhutilArgumentUsageException(pht('Unable to load subscription with PHID "%s".', $subscription_phid));
     }
     $now = $args->getArg('now');
     $now = $this->parseTimeArgument($now);
     if (!$now) {
         $now = PhabricatorTime::getNow();
     }
     $time_guard = PhabricatorTime::pushTime($now, date_default_timezone_get());
     $console->writeOut("%s\n", pht('Set current time to %s.', phabricator_datetime(PhabricatorTime::getNow(), $viewer)));
     $auto_range = $args->getArg('auto-range');
     $last_arg = $args->getArg('last');
     $next_arg = $args->getARg('next');
     if (!$auto_range && !$last_arg && !$next_arg) {
         throw new PhutilArgumentUsageException(pht('Specify a billing range with %s and %s, or use %s.', '--last', '--next', '--auto-range'));
     } else {
         if (!$auto_range & (!$last_arg || !$next_arg)) {
             throw new PhutilArgumentUsageException(pht('When specifying %s or %s, you must specify both arguments ' . 'to define the beginning and end of the billing range.', '--last', '--next'));
         } else {
             if (!$auto_range && ($last_arg && $next_arg)) {
                 $last_time = $this->parseTimeArgument($args->getArg('last'));
                 $next_time = $this->parseTimeArgument($args->getArg('next'));
             } else {
                 if ($auto_range && ($last_arg || $next_arg)) {
                     throw new PhutilArgumentUsageException(pht('Use either %s or %s and %s to specify the ' . 'billing range, but not both.', '--auto-range', '--last', '--next'));
                 } else {
                     $trigger = $subscription->getTrigger();
                     $event = $trigger->getEvent();
                     if (!$event) {
                         throw new PhutilArgumentUsageException(pht('Unable to calculate %s, this subscription has not been ' . 'scheduled for billing yet. Wait for the trigger daemon to ' . 'schedule the subscription.', '--auto-range'));
                     }
                     $last_time = $event->getLastEventEpoch();
                     $next_time = $event->getNextEventEpoch();
                 }
             }
         }
     }
     $console->writeOut("%s\n", pht('Preparing to invoice subscription "%s" from %s to %s.', $subscription->getSubscriptionName(), $last_time ? phabricator_datetime($last_time, $viewer) : pht('subscription creation'), phabricator_datetime($next_time, $viewer)));
     PhabricatorWorker::setRunAllTasksInProcess(true);
     if (!$args->getArg('force')) {
         $console->writeOut("**<bg:yellow> %s </bg>**\n%s\n", pht('WARNING'), phutil_console_wrap(pht('Manually invoicing will double bill payment accounts if the ' . 'range overlaps an existing or future invoice. This script is ' . 'intended for testing and development, and should not be part ' . 'of routine billing operations. If you continue, you may ' . 'incorrectly overcharge customers.')));
         if (!phutil_console_confirm(pht('Really invoice this subscription?'))) {
             throw new Exception(pht('Declining to invoice.'));
         }
     }
     PhabricatorWorker::scheduleTask('PhortuneSubscriptionWorker', array('subscriptionPHID' => $subscription->getPHID(), 'trigger.last-epoch' => $last_time, 'trigger.this-epoch' => $next_time, 'manual' => true), array('objectPHID' => $subscription->getPHID()));
     return 0;
 }
 public function execute(PhutilArgumentParser $args)
 {
     $viewer = $this->getViewer();
     $ids = $args->getArg('id');
     $active = $args->getArg('active');
     if (!$ids && !$active) {
         throw new PhutilArgumentUsageException(pht('Use --id or --active to select builds.'));
     }
     if ($ids && $active) {
         throw new PhutilArgumentUsageException(pht('Use one of --id or --active to select builds, but not both.'));
     }
     $query = id(new HarbormasterBuildQuery())->setViewer($viewer);
     if ($ids) {
         $query->withIDs($ids);
     } else {
         $query->withBuildStatuses(HarbormasterBuildStatus::getActiveStatusConstants());
     }
     $builds = $query->execute();
     $console = PhutilConsole::getConsole();
     $count = count($builds);
     if (!$count) {
         $console->writeOut("%s\n", pht('No builds to restart.'));
         return 0;
     }
     $prompt = pht('Restart %s build(s)?', new PhutilNumber($count));
     if (!phutil_console_confirm($prompt)) {
         $console->writeOut("%s\n", pht('Cancelled.'));
         return 1;
     }
     $app_phid = id(new PhabricatorHarbormasterApplication())->getPHID();
     $editor = id(new HarbormasterBuildTransactionEditor())->setActor($viewer)->setActingAsPHID($app_phid)->setContentSource($this->newContentSource());
     foreach ($builds as $build) {
         $console->writeOut("<bg:blue> %s </bg> %s\n", pht('RESTARTING'), pht('Build %d: %s', $build->getID(), $build->getName()));
         if (!$build->canRestartBuild()) {
             $console->writeOut("<bg:yellow> %s </bg> %s\n", pht('INVALID'), pht('Cannot be restarted.'));
             continue;
         }
         $xactions = array();
         $xactions[] = id(new HarbormasterBuildTransaction())->setTransactionType(HarbormasterBuildTransaction::TYPE_COMMAND)->setNewValue(HarbormasterBuildCommand::COMMAND_RESTART);
         try {
             $editor->applyTransactions($build, $xactions);
         } catch (Exception $e) {
             $message = phutil_console_wrap($e->getMessage(), 2);
             $console->writeOut("<bg:red> %s </bg>\n%s\n", pht('FAILED'), $message);
             continue;
         }
         $console->writeOut("<bg:green> %s </bg>\n", pht('SUCCESS'));
     }
     return 0;
 }
 public function execute(PhutilArgumentParser $args)
 {
     $config_key = 'phabricator.developer-mode';
     if (!PhabricatorEnv::getEnvConfig($config_key)) {
         throw new PhutilArgumentUsageException(pht('lipsum is a development and testing tool and may only be run ' . 'on installs in developer mode. Enable "%s" in your configuration ' . 'to enable lipsum.', $config_key));
     }
     $all_generators = id(new PhutilClassMapQuery())->setAncestorClass('PhabricatorTestDataGenerator')->execute();
     $argv = $args->getArg('args');
     $all = 'all';
     if (!$argv) {
         $names = mpull($all_generators, 'getGeneratorName');
         sort($names);
         $list = id(new PhutilConsoleList())->setWrap(false)->addItems($names);
         id(new PhutilConsoleBlock())->addParagraph(pht('Choose which type or types of test data you want to generate, ' . 'or select "%s".', $all))->addList($list)->draw();
         return 0;
     }
     $generators = array();
     foreach ($argv as $arg_original) {
         $arg = phutil_utf8_strtolower($arg_original);
         $match = false;
         foreach ($all_generators as $generator) {
             $name = phutil_utf8_strtolower($generator->getGeneratorName());
             if ($arg == $all) {
                 $generators[] = $generator;
                 $match = true;
                 break;
             }
             if (strpos($name, $arg) !== false) {
                 $generators[] = $generator;
                 $match = true;
                 break;
             }
         }
         if (!$match) {
             throw new PhutilArgumentUsageException(pht('Argument "%s" does not match the name of any generators.', $arg_original));
         }
     }
     echo tsprintf("**<bg:blue> %s </bg>** %s\n", pht('GENERATORS'), pht('Selected generators: %s.', implode(', ', mpull($generators, 'getGeneratorName'))));
     echo tsprintf("**<bg:yellow> %s </bg>** %s\n", pht('WARNING'), pht('This command generates synthetic test data, including user ' . 'accounts. It is intended for use in development environments ' . 'so you can test features more easily. There is no easy way to ' . 'delete this data or undo the effects of this command. If you run ' . 'it in a production environment, it will pollute your data with ' . 'large amounts of meaningless garbage that you can not get rid of.'));
     $prompt = pht('Are you sure you want to generate piles of garbage?');
     if (!phutil_console_confirm($prompt, true)) {
         return;
     }
     echo tsprintf("**<bg:green> %s </bg>** %s\n", pht('LIPSUM'), pht('Generating synthetic test objects forever. ' . 'Use ^C to stop when satisfied.'));
     $this->generate($generators);
 }
 public function didExecute(PhutilArgumentParser $args)
 {
     $console = PhutilConsole::getConsole();
     if (!$this->isDryRun() && !$this->isForce()) {
         $console->writeOut(phutil_console_wrap(pht('Are you completely sure you really want to permanently destroy ' . 'all storage for Phabricator data? This operation can not be ' . 'undone and your data will not be recoverable if you proceed.')));
         if (!phutil_console_confirm(pht('Permanently destroy all data?'))) {
             $console->writeOut("%s\n", pht('Cancelled.'));
             exit(1);
         }
         if (!phutil_console_confirm(pht('Really destroy all data forever?'))) {
             $console->writeOut("%s\n", pht('Cancelled.'));
             exit(1);
         }
     }
     $apis = $this->getMasterAPIs();
     foreach ($apis as $api) {
         $patches = $this->getPatches();
         if ($args->getArg('unittest-fixtures')) {
             $conn = $api->getConn(null);
             $databases = queryfx_all($conn, 'SELECT DISTINCT(TABLE_SCHEMA) AS db ' . 'FROM INFORMATION_SCHEMA.TABLES ' . 'WHERE TABLE_SCHEMA LIKE %>', PhabricatorTestCase::NAMESPACE_PREFIX);
             $databases = ipull($databases, 'db');
         } else {
             $databases = $api->getDatabaseList($patches);
             $databases[] = $api->getDatabaseName('meta_data');
             // These are legacy databases that were dropped long ago. See T2237.
             $databases[] = $api->getDatabaseName('phid');
             $databases[] = $api->getDatabaseName('directory');
         }
         foreach ($databases as $database) {
             if ($this->isDryRun()) {
                 $console->writeOut("%s\n", pht("DRYRUN: Would drop database '%s'.", $database));
             } else {
                 $console->writeOut("%s\n", pht("Dropping database '%s'...", $database));
                 queryfx($api->getConn(null), 'DROP DATABASE IF EXISTS %T', $database);
             }
         }
         if (!$this->isDryRun()) {
             $console->writeOut("%s\n", pht('Storage on "%s" was destroyed.', $api->getRef()->getRefKey()));
         }
     }
     return 0;
 }
 public function execute(PhutilArgumentParser $args)
 {
     $is_dry = $args->getArg('dryrun');
     $is_force = $args->getArg('force');
     if (!$is_dry && !$is_force) {
         echo phutil_console_wrap('Are you completely sure you really want to permanently destroy all ' . 'storage for Phabricator data? This operation can not be undone and ' . 'your data will not be recoverable if you proceed.');
         if (!phutil_console_confirm('Permanently destroy all data?')) {
             echo "Cancelled.\n";
             exit(1);
         }
         if (!phutil_console_confirm('Really destroy all data forever?')) {
             echo "Cancelled.\n";
             exit(1);
         }
     }
     $api = $this->getAPI();
     $patches = $this->getPatches();
     if ($args->getArg('unittest-fixtures')) {
         $conn = $api->getConn(null);
         $databases = queryfx_all($conn, 'SELECT DISTINCT(TABLE_SCHEMA) AS db ' . 'FROM INFORMATION_SCHEMA.TABLES ' . 'WHERE TABLE_SCHEMA LIKE %>', PhabricatorTestCase::NAMESPACE_PREFIX);
         $databases = ipull($databases, 'db');
     } else {
         $databases = $api->getDatabaseList($patches);
         $databases[] = $api->getDatabaseName('meta_data');
         // These are legacy databases that were dropped long ago. See T2237.
         $databases[] = $api->getDatabaseName('phid');
         $databases[] = $api->getDatabaseName('directory');
     }
     foreach ($databases as $database) {
         if ($is_dry) {
             echo "DRYRUN: Would drop database '{$database}'.\n";
         } else {
             echo "Dropping database '{$database}'...\n";
             queryfx($api->getConn(null), 'DROP DATABASE IF EXISTS %T', $database);
         }
     }
     if (!$is_dry) {
         echo "Storage was destroyed.\n";
     }
     return 0;
 }
 public function run()
 {
     $is_show = $this->getArgument('show');
     $repository_api = $this->getRepositoryAPI();
     if (!$is_show) {
         if (!$repository_api->supportsAmend()) {
             throw new ArcanistUsageException(pht("You may only run '%s' in a git or hg " . "(version 2.2 or newer) working copy.", 'arc amend'));
         }
         if ($this->isHistoryImmutable()) {
             throw new ArcanistUsageException(pht('This project is marked as adhering to a conservative history ' . 'mutability doctrine (having an immutable local history), which ' . 'precludes amending commit messages.'));
         }
         if ($repository_api->getUncommittedChanges()) {
             throw new ArcanistUsageException(pht('You have uncommitted changes in this branch. Stage and commit ' . '(or revert) them before proceeding.'));
         }
     }
     $revision_id = null;
     if ($this->getArgument('revision')) {
         $revision_id = $this->normalizeRevisionID($this->getArgument('revision'));
     }
     $repository_api->setBaseCommitArgumentRules('arc:this');
     $in_working_copy = $repository_api->loadWorkingCopyDifferentialRevisions($this->getConduit(), array('status' => 'status-any'));
     $in_working_copy = ipull($in_working_copy, null, 'id');
     if (!$revision_id) {
         if (count($in_working_copy) == 0) {
             throw new ArcanistUsageException(pht("No revision specified with '%s', and no revisions found " . "in the working copy. Use '%s' to specify which revision " . "you want to amend.", '--revision', '--revision <id>'));
         } else {
             if (count($in_working_copy) > 1) {
                 $message = pht("More than one revision was found in the working copy:\n%s\n" . "Use '%s' to specify which revision you want to amend.", $this->renderRevisionList($in_working_copy), '--revision <id>');
                 throw new ArcanistUsageException($message);
             } else {
                 $revision_id = key($in_working_copy);
                 $revision = $in_working_copy[$revision_id];
                 if ($revision['authorPHID'] != $this->getUserPHID()) {
                     $other_author = $this->getConduit()->callMethodSynchronous('user.query', array('phids' => array($revision['authorPHID'])));
                     $other_author = ipull($other_author, 'userName', 'phid');
                     $other_author = $other_author[$revision['authorPHID']];
                     $rev_title = $revision['title'];
                     $ok = phutil_console_confirm(pht("You are amending the revision '%s' but you are not " . "the author. Amend this revision by %s?", "D{$revision_id}: {$rev_title}", $other_author));
                     if (!$ok) {
                         throw new ArcanistUserAbortException();
                     }
                 }
             }
         }
     }
     $conduit = $this->getConduit();
     try {
         $message = $conduit->callMethodSynchronous('differential.getcommitmessage', array('revision_id' => $revision_id, 'edit' => false));
     } catch (ConduitClientException $ex) {
         if (strpos($ex->getMessage(), 'ERR_NOT_FOUND') === false) {
             throw $ex;
         } else {
             throw new ArcanistUsageException(pht("Revision '%s' does not exist.", "D{$revision_id}"));
         }
     }
     $revision = $conduit->callMethodSynchronous('differential.query', array('ids' => array($revision_id)));
     if (empty($revision)) {
         throw new Exception(pht("Failed to lookup information for '%s'!", "D{$revision_id}"));
     }
     $revision = head($revision);
     $revision_title = $revision['title'];
     if (!$is_show) {
         if ($revision_id && empty($in_working_copy[$revision_id])) {
             $ok = phutil_console_confirm(pht("The revision '%s' does not appear to be in the working copy. Are " . "you sure you want to amend HEAD with the commit message for '%s'?", "D{$revision_id}", "D{$revision_id}: {$revision_title}"));
             if (!$ok) {
                 throw new ArcanistUserAbortException();
             }
         }
     }
     if ($is_show) {
         echo $message . "\n";
     } else {
         echo pht("Amending commit message to reflect revision %s.\n", phutil_console_format('**D%d: %s**', $revision_id, $revision_title));
         $repository_api->amendCommit($message);
     }
     return 0;
 }
Esempio n. 15
0
define('SCHEMA_VERSION_TABLE_NAME', 'schema_version');
// TODO: getopt() is super terrible, move to something less terrible.
$options = getopt('fhv:u:p:') + array('v' => null, 'u' => null, 'p' => null);
foreach (array('h', 'f') as $key) {
    // By default, these keys are set to 'false' to indicate that the flag was
    // passed.
    if (array_key_exists($key, $options)) {
        $options[$key] = true;
    }
}
if (!empty($options['h']) || $options['v'] && !is_numeric($options['v'])) {
    usage();
}
if (empty($options['f'])) {
    echo phutil_console_wrap("Before running this script, you should take down the Phabricator web " . "interface and stop any running Phabricator daemons.");
    if (!phutil_console_confirm('Are you ready to continue?')) {
        echo "Cancelled.\n";
        exit(1);
    }
}
// Use always the version from the commandline if it is defined
$next_version = isset($options['v']) ? (int) $options['v'] : null;
$conf = DatabaseConfigurationProvider::getConfiguration();
if ($options['u']) {
    $conn_user = $options['u'];
    $conn_pass = $options['p'];
} else {
    $conn_user = $conf->getUser();
    $conn_pass = $conf->getPassword();
}
$conn_host = $conf->getHost();
Esempio n. 16
0
 private function uploadFilesForChanges(array $changes)
 {
     assert_instances_of($changes, 'ArcanistDiffChange');
     // Collect all the files we need to upload.
     $need_upload = array();
     foreach ($changes as $key => $change) {
         if ($change->getFileType() != ArcanistDiffChangeType::FILE_BINARY) {
             continue;
         }
         if ($this->getArgument('skip-binaries')) {
             continue;
         }
         $name = basename($change->getCurrentPath());
         $need_upload[] = array('type' => 'old', 'name' => $name, 'data' => $change->getOriginalFileData(), 'change' => $change);
         $need_upload[] = array('type' => 'new', 'name' => $name, 'data' => $change->getCurrentFileData(), 'change' => $change);
     }
     if (!$need_upload) {
         return;
     }
     // Determine mime types and file sizes. Update changes from "binary" to
     // "image" if the file is an image. Set image metadata.
     $type_image = ArcanistDiffChangeType::FILE_IMAGE;
     foreach ($need_upload as $key => $spec) {
         $change = $need_upload[$key]['change'];
         $type = $spec['type'];
         $size = strlen($spec['data']);
         $change->setMetadata("{$type}:file:size", $size);
         if ($spec['data'] === null) {
             // This covers the case where a file was added or removed; we don't
             // need to upload the other half of it (e.g., the old file data for
             // a file which was just added). This is distinct from an empty
             // file, which we do upload.
             unset($need_upload[$key]);
             continue;
         }
         $mime = $this->getFileMimeType($spec['data']);
         if (preg_match('@^image/@', $mime)) {
             $change->setFileType($type_image);
         }
         $change->setMetadata("{$type}:file:mime-type", $mime);
     }
     $uploader = id(new ArcanistFileUploader())->setConduitClient($this->getConduit());
     foreach ($need_upload as $key => $spec) {
         $ref = id(new ArcanistFileDataRef())->setName($spec['name'])->setData($spec['data']);
         $uploader->addFile($ref, $key);
     }
     $files = $uploader->uploadFiles();
     $errors = false;
     foreach ($files as $key => $file) {
         if ($file->getErrors()) {
             unset($files[$key]);
             $errors = true;
             echo pht('Failed to upload binary "%s".', $file->getName());
         }
     }
     if ($errors) {
         $prompt = pht('Continue?');
         $ok = phutil_console_confirm($prompt, $default_no = false);
         if (!$ok) {
             throw new ArcanistUsageException(pht('Aborted due to file upload failure. You can use %s ' . 'to skip binary uploads.', '--skip-binaries'));
         }
     }
     foreach ($files as $key => $file) {
         $spec = $need_upload[$key];
         $phid = $file->getPHID();
         $change = $spec['change'];
         $type = $spec['type'];
         $change->setMetadata("{$type}:binary-phid", $phid);
         echo pht('Uploaded binary data for "%s".', $file->getName()) . "\n";
     }
     echo pht('Upload complete.') . "\n";
 }
 public function handleMessage(PhutilConsoleMessage $message)
 {
     $data = $message->getData();
     $type = $message->getType();
     switch ($type) {
         case PhutilConsoleMessage::TYPE_CONFIRM:
             $ok = phutil_console_confirm($data['prompt'], !$data['default']);
             return $this->buildMessage(PhutilConsoleMessage::TYPE_INPUT, $ok);
         case PhutilConsoleMessage::TYPE_PROMPT:
             $response = phutil_console_prompt($data['prompt'], idx($data, 'history'));
             return $this->buildMessage(PhutilConsoleMessage::TYPE_INPUT, $response);
         case PhutilConsoleMessage::TYPE_OUT:
             $this->writeText(STDOUT, $data);
             return null;
         case PhutilConsoleMessage::TYPE_ERR:
             $this->writeText(STDERR, $data);
             return null;
         case PhutilConsoleMessage::TYPE_LOG:
             if ($this->enableLog) {
                 $this->writeText(STDERR, $data);
             }
             return null;
         case PhutilConsoleMessage::TYPE_ENABLED:
             switch ($data['which']) {
                 case PhutilConsoleMessage::TYPE_LOG:
                     $enabled = $this->enableLog;
                     break;
                 default:
                     $enabled = true;
                     break;
             }
             return $this->buildMessage(PhutilConsoleMessage::TYPE_IS_ENABLED, $enabled);
         case PhutilConsoleMessage::TYPE_TTY:
         case PhutilConsoleMessage::TYPE_COLS:
             switch ($data['which']) {
                 case PhutilConsoleMessage::TYPE_OUT:
                     $which = STDOUT;
                     break;
                 case PhutilConsoleMessage::TYPE_ERR:
                     $which = STDERR;
                     break;
             }
             switch ($type) {
                 case PhutilConsoleMessage::TYPE_TTY:
                     if (function_exists('posix_isatty')) {
                         $is_a_tty = posix_isatty($which);
                     } else {
                         $is_a_tty = null;
                     }
                     return $this->buildMessage(PhutilConsoleMessage::TYPE_IS_TTY, $is_a_tty);
                 case PhutilConsoleMessage::TYPE_COLS:
                     // TODO: This is an approximation which might not be perfectly
                     // accurate.
                     $width = phutil_console_get_terminal_width();
                     return $this->buildMessage(PhutilConsoleMessage::TYPE_COL_WIDTH, $width);
             }
             break;
         default:
             if ($this->handler) {
                 return call_user_func($this->handler, $message);
             } else {
                 throw new Exception(pht("Received unknown console message of type '%s'.", $type));
             }
     }
 }
 private function uploadFilesForChanges(array $changes)
 {
     assert_instances_of($changes, 'ArcanistDiffChange');
     // Collect all the files we need to upload.
     $need_upload = array();
     foreach ($changes as $key => $change) {
         if ($change->getFileType() != ArcanistDiffChangeType::FILE_BINARY) {
             continue;
         }
         if ($this->getArgument('skip-binaries')) {
             continue;
         }
         $name = basename($change->getCurrentPath());
         $need_upload[] = array('type' => 'old', 'name' => $name, 'data' => $change->getOriginalFileData(), 'change' => $change);
         $need_upload[] = array('type' => 'new', 'name' => $name, 'data' => $change->getCurrentFileData(), 'change' => $change);
     }
     if (!$need_upload) {
         return;
     }
     // Determine mime types and file sizes. Update changes from "binary" to
     // "image" if the file is an image. Set image metadata.
     $type_image = ArcanistDiffChangeType::FILE_IMAGE;
     foreach ($need_upload as $key => $spec) {
         $change = $need_upload[$key]['change'];
         $type = $spec['type'];
         $size = strlen($spec['data']);
         $change->setMetadata("{$type}:file:size", $size);
         if ($spec['data'] === null) {
             // This covers the case where a file was added or removed; we don't
             // need to upload it. (This is distinct from an empty file, which we
             // do upload.)
             unset($need_upload[$key]);
             continue;
         }
         $mime = $this->getFileMimeType($spec['data']);
         if (preg_match('@^image/@', $mime)) {
             $change->setFileType($type_image);
         }
         $change->setMetadata("{$type}:file:mime-type", $mime);
     }
     echo pht("Uploading %d files...", count($need_upload)) . "\n";
     // Now we're ready to upload the actual file data. If possible, we'll just
     // transmit a hash of the file instead of the actual file data. If the data
     // already exists, Phabricator can share storage. Check if we can use
     // "file.uploadhash" yet (i.e., if the server is up to date enough).
     // TODO: Drop this check once we bump the protocol version.
     $conduit_methods = $this->getConduit()->callMethodSynchronous('conduit.query', array());
     $can_use_hash_upload = isset($conduit_methods['file.uploadhash']);
     if ($can_use_hash_upload) {
         $hash_futures = array();
         foreach ($need_upload as $key => $spec) {
             $hash_futures[$key] = $this->getConduit()->callMethod('file.uploadhash', array('name' => $spec['name'], 'hash' => sha1($spec['data'])));
         }
         foreach (Futures($hash_futures)->limit(8) as $key => $future) {
             $type = $need_upload[$key]['type'];
             $change = $need_upload[$key]['change'];
             $name = $need_upload[$key]['name'];
             $phid = null;
             try {
                 $phid = $future->resolve();
             } catch (Exception $e) {
                 // Just try uploading normally if the hash upload failed.
                 continue;
             }
             if ($phid) {
                 $change->setMetadata("{$type}:binary-phid", $phid);
                 unset($need_upload[$key]);
                 echo pht("Uploaded '%s' (%s).", $name, $type) . "\n";
             }
         }
     }
     $upload_futures = array();
     foreach ($need_upload as $key => $spec) {
         $upload_futures[$key] = $this->getConduit()->callMethod('file.upload', array('name' => $spec['name'], 'data_base64' => base64_encode($spec['data'])));
     }
     foreach (Futures($upload_futures)->limit(4) as $key => $future) {
         $type = $need_upload[$key]['type'];
         $change = $need_upload[$key]['change'];
         $name = $need_upload[$key]['name'];
         try {
             $phid = $future->resolve();
             $change->setMetadata("{$type}:binary-phid", $phid);
             echo pht("Uploaded '%s' (%s).", $name, $type) . "\n";
         } catch (Exception $e) {
             echo "Failed to upload {$type} binary '{$name}'.\n";
             if (!phutil_console_confirm('Continue?', $default_no = false)) {
                 throw new ArcanistUsageException('Aborted due to file upload failure. You can use --skip-binaries ' . 'to skip binary uploads.');
             }
         }
     }
     echo pht("Upload complete.") . "\n";
 }
 /**
  * Do the best we can to prevent PEBKAC and id10t issues.
  */
 private function sanityCheck(ArcanistBundle $bundle)
 {
     $repository_api = $this->getRepositoryAPI();
     // Check to see if the bundle's base revision matches the working copy
     // base revision
     if ($repository_api->supportsLocalCommits()) {
         $bundle_base_rev = $bundle->getBaseRevision();
         if (empty($bundle_base_rev)) {
             // this means $source is SOURCE_PATCH || SOURCE_BUNDLE w/ $version < 2
             // they don't have a base rev so just do nothing
             $commit_exists = true;
         } else {
             $commit_exists = $repository_api->hasLocalCommit($bundle_base_rev);
         }
         if (!$commit_exists) {
             // we have a problem...! lots of work because we need to ask
             // differential for revision information for these base revisions
             // to improve our error message.
             $bundle_base_rev_str = null;
             $source_base_rev = $repository_api->getWorkingCopyRevision();
             $source_base_rev_str = null;
             if ($repository_api instanceof ArcanistGitAPI) {
                 $hash_type = ArcanistDifferentialRevisionHash::HASH_GIT_COMMIT;
             } else {
                 if ($repository_api instanceof ArcanistMercurialAPI) {
                     $hash_type = ArcanistDifferentialRevisionHash::HASH_MERCURIAL_COMMIT;
                 } else {
                     $hash_type = null;
                 }
             }
             if ($hash_type) {
                 // 2 round trips because even though we could send off one query
                 // we wouldn't be able to tell which revisions were for which hash
                 $hash = array($hash_type, $bundle_base_rev);
                 $bundle_revision = $this->loadRevisionFromHash($hash);
                 $hash = array($hash_type, $source_base_rev);
                 $source_revision = $this->loadRevisionFromHash($hash);
                 if ($bundle_revision) {
                     $bundle_base_rev_str = $bundle_base_rev . ' \\ D' . $bundle_revision['id'];
                 }
                 if ($source_revision) {
                     $source_base_rev_str = $source_base_rev . ' \\ D' . $source_revision['id'];
                 }
             }
             $bundle_base_rev_str = nonempty($bundle_base_rev_str, $bundle_base_rev);
             $source_base_rev_str = nonempty($source_base_rev_str, $source_base_rev);
             $ok = phutil_console_confirm(pht('This diff is against commit %s, but the commit is nowhere ' . 'in the working copy. Try to apply it against the current ' . 'working copy state? (%s)', $bundle_base_rev_str, $source_base_rev_str), $default_no = false);
             if (!$ok) {
                 throw new ArcanistUserAbortException();
             }
         }
     }
 }
Esempio n. 20
0
 public function run()
 {
     $working_copy = $this->getWorkingCopy();
     $engine = $this->getArgument('engine');
     if (!$engine) {
         $engine = $working_copy->getConfigFromAnySource('lint.engine');
         if (!$engine) {
             throw new ArcanistNoEngineException("No lint engine configured for this project. Edit .arcconfig to " . "specify a lint engine.");
         }
     }
     $rev = $this->getArgument('rev');
     $paths = $this->getArgument('paths');
     if ($rev && $paths) {
         throw new ArcanistUsageException("Specify either --rev or paths.");
     }
     $should_lint_all = $this->getArgument('lintall');
     if ($paths) {
         // NOTE: When the user specifies paths, we imply --lintall and show all
         // warnings for the paths in question. This is easier to deal with for
         // us and less confusing for users.
         $should_lint_all = true;
     }
     $paths = $this->selectPathsForWorkflow($paths, $rev);
     // is_subclass_of() doesn't autoload under HPHP.
     if (!class_exists($engine) || !is_subclass_of($engine, 'ArcanistLintEngine')) {
         throw new ArcanistUsageException("Configured lint engine '{$engine}' is not a subclass of " . "'ArcanistLintEngine'.");
     }
     $engine = newv($engine, array());
     $this->engine = $engine;
     $engine->setWorkingCopy($working_copy);
     if ($this->getArgument('advice')) {
         $engine->setMinimumSeverity(ArcanistLintSeverity::SEVERITY_ADVICE);
     } else {
         $engine->setMinimumSeverity(ArcanistLintSeverity::SEVERITY_AUTOFIX);
     }
     // Propagate information about which lines changed to the lint engine.
     // This is used so that the lint engine can drop warning messages
     // concerning lines that weren't in the change.
     $engine->setPaths($paths);
     if (!$should_lint_all) {
         foreach ($paths as $path) {
             // Note that getChangedLines() returns null to indicate that a file
             // is binary or a directory (i.e., changed lines are not relevant).
             $engine->setPathChangedLines($path, $this->getChangedLines($path, 'new'));
         }
     }
     // Enable possible async linting only for 'arc diff' not 'arc unit'
     if ($this->getParentWorkflow()) {
         $engine->setEnableAsyncLint(true);
     } else {
         $engine->setEnableAsyncLint(false);
     }
     $results = $engine->run();
     // It'd be nice to just return a single result from the run method above
     // which contains both the lint messages and the postponed linters.
     // However, to maintain compatibility with existing lint subclasses, use
     // a separate method call to grab the postponed linters.
     $this->postponedLinters = $engine->getPostponedLinters();
     if ($this->getArgument('never-apply-patches')) {
         $apply_patches = false;
     } else {
         $apply_patches = true;
     }
     if ($this->getArgument('apply-patches')) {
         $prompt_patches = false;
     } else {
         $prompt_patches = true;
     }
     if ($this->getArgument('amend-all')) {
         $this->shouldAmendChanges = true;
         $this->shouldAmendWithoutPrompt = true;
     }
     if ($this->getArgument('amend-autofixes')) {
         $prompt_autofix_patches = false;
         $this->shouldAmendChanges = true;
         $this->shouldAmendAutofixesWithoutPrompt = true;
     } else {
         $prompt_autofix_patches = true;
     }
     $wrote_to_disk = false;
     switch ($this->getArgument('output')) {
         case 'json':
             $renderer = new ArcanistLintJSONRenderer();
             $prompt_patches = false;
             $apply_patches = $this->getArgument('apply-patches');
             break;
         case 'summary':
             $renderer = new ArcanistLintSummaryRenderer();
             break;
         case 'compiler':
             $renderer = new ArcanistLintLikeCompilerRenderer();
             $prompt_patches = false;
             $apply_patches = $this->getArgument('apply-patches');
             break;
         default:
             $renderer = new ArcanistLintConsoleRenderer();
             $renderer->setShowAutofixPatches($prompt_autofix_patches);
             break;
     }
     $all_autofix = true;
     foreach ($results as $result) {
         $result_all_autofix = $result->isAllAutofix();
         if (!$result->getMessages() && !$result_all_autofix) {
             continue;
         }
         if (!$result_all_autofix) {
             $all_autofix = false;
         }
         $lint_result = $renderer->renderLintResult($result);
         if ($lint_result) {
             echo $lint_result;
         }
         if ($apply_patches && $result->isPatchable()) {
             $patcher = ArcanistLintPatcher::newFromArcanistLintResult($result);
             if ($prompt_patches && !($result_all_autofix && !$prompt_autofix_patches)) {
                 $old_file = $result->getFilePathOnDisk();
                 if (!Filesystem::pathExists($old_file)) {
                     $old_file = '/dev/null';
                 }
                 $new_file = new TempFile();
                 $new = $patcher->getModifiedFileContent();
                 Filesystem::writeFile($new_file, $new);
                 // TODO: Improve the behavior here, make it more like
                 // difference_render().
                 passthru(csprintf("diff -u %s %s", $old_file, $new_file));
                 $prompt = phutil_console_format("Apply this patch to __%s__?", $result->getPath());
                 if (!phutil_console_confirm($prompt, $default_no = false)) {
                     continue;
                 }
             }
             $patcher->writePatchToDisk();
             $wrote_to_disk = true;
         }
     }
     $repository_api = $this->getRepositoryAPI();
     if ($wrote_to_disk && $repository_api instanceof ArcanistGitAPI && $this->shouldAmendChanges) {
         if ($this->shouldAmendWithoutPrompt || $this->shouldAmendAutofixesWithoutPrompt && $all_autofix) {
             echo phutil_console_format("<bg:yellow>** LINT NOTICE **</bg> Automatically amending HEAD " . "with lint patches.\n");
             $amend = true;
         } else {
             $amend = phutil_console_confirm("Amend HEAD with lint patches?");
         }
         if ($amend) {
             execx('(cd %s; git commit -a --amend -C HEAD)', $repository_api->getPath());
         } else {
             throw new ArcanistUsageException("Sort out the lint changes that were applied to the working " . "copy and relint.");
         }
     }
     $unresolved = array();
     $has_warnings = false;
     $has_errors = false;
     foreach ($results as $result) {
         foreach ($result->getMessages() as $message) {
             if (!$message->isPatchApplied()) {
                 if ($message->isError()) {
                     $has_errors = true;
                 } else {
                     if ($message->isWarning()) {
                         $has_warnings = true;
                     }
                 }
                 $unresolved[] = $message;
             }
         }
     }
     $this->unresolvedMessages = $unresolved;
     // Take the most severe lint message severity and use that
     // as the result code.
     if ($has_errors) {
         $result_code = self::RESULT_ERRORS;
     } else {
         if ($has_warnings) {
             $result_code = self::RESULT_WARNINGS;
         } else {
             if (!empty($this->postponedLinters)) {
                 $result_code = self::RESULT_POSTPONED;
             } else {
                 $result_code = self::RESULT_OKAY;
             }
         }
     }
     if (!$this->getParentWorkflow()) {
         if ($result_code == self::RESULT_OKAY) {
             echo $renderer->renderOkayResult();
         }
     }
     return $result_code;
 }
Esempio n. 21
0
 /**
  * @task message
  */
 private function validateCommitMessage(ArcanistDifferentialCommitMessage $message)
 {
     $reviewers = $message->getFieldValue('reviewerPHIDs');
     if (!$reviewers) {
         $confirm = "You have not specified any reviewers. Continue anyway?";
         if (!phutil_console_confirm($confirm)) {
             throw new ArcanistUsageException('Specify reviewers and retry.');
         }
     } else {
         if (in_array($this->getUserPHID(), $reviewers)) {
             throw new ArcanistUsageException("You can not be a reviewer for your own revision.");
         } else {
             $users = $this->getConduit()->callMethodSynchronous('user.query', array('phids' => $reviewers));
             $untils = array();
             foreach ($users as $user) {
                 if (idx($user, 'currentStatus') == 'away') {
                     $untils[] = $user['currentStatusUntil'];
                 }
             }
             if (count($untils) == count($reviewers)) {
                 $until = date('l, M j Y', min($untils));
                 $confirm = "All reviewers are away until {$until}. Continue anyway?";
                 if (!phutil_console_confirm($confirm)) {
                     throw new ArcanistUsageException('Specify available reviewers and retry.');
                 }
             }
         }
     }
 }
 public static function readUserConfigurationFile()
 {
     $user_config = array();
     $user_config_path = self::getUserConfigurationFileLocation();
     if (Filesystem::pathExists($user_config_path)) {
         if (!phutil_is_windows()) {
             $mode = fileperms($user_config_path);
             if (!$mode) {
                 throw new Exception("Unable to get perms of '{$user_config_path}'!");
             }
             if ($mode & 0177) {
                 // Mode should allow only owner access.
                 $prompt = "File permissions on your ~/.arcrc are too open. " . "Fix them by chmod'ing to 600?";
                 if (!phutil_console_confirm($prompt, $default_no = false)) {
                     throw new ArcanistUsageException("Set ~/.arcrc to file mode 600.");
                 }
                 execx('chmod 600 %s', $user_config_path);
                 // Drop the stat cache so we don't read the old permissions if
                 // we end up here again. If we don't do this, we may prompt the user
                 // to fix permissions multiple times.
                 clearstatcache();
             }
         }
         $user_config_data = Filesystem::readFile($user_config_path);
         $user_config = json_decode($user_config_data, true);
         if (!is_array($user_config)) {
             throw new ArcanistUsageException("Your '~/.arcrc' file is not a valid JSON file.");
         }
     }
     return $user_config;
 }
Esempio n. 23
0
 private function askForAdd(array $files)
 {
     if ($this->commitMode == self::COMMIT_DISABLE) {
         return false;
     }
     if ($this->commitMode == self::COMMIT_ENABLE) {
         return true;
     }
     $prompt = $this->getAskForAddPrompt($files);
     return phutil_console_confirm($prompt);
 }
 public function run()
 {
     $is_finalize = $this->getArgument('finalize');
     $conduit = $this->getConduit();
     $revision_list = $this->getArgument('revision', array());
     if (!$revision_list) {
         throw new ArcanistUsageException("close-revision requires a revision number.");
     }
     if (count($revision_list) != 1) {
         throw new ArcanistUsageException("close-revision requires exactly one revision.");
     }
     $revision_id = reset($revision_list);
     $revision_id = $this->normalizeRevisionID($revision_id);
     $revision = null;
     try {
         $revision = $conduit->callMethodSynchronous('differential.getrevision', array('revision_id' => $revision_id));
     } catch (Exception $ex) {
         if (!$is_finalize) {
             throw new ArcanistUsageException("Revision D{$revision_id} does not exist.");
         }
     }
     $status_accepted = ArcanistDifferentialRevisionStatus::ACCEPTED;
     $status_closed = ArcanistDifferentialRevisionStatus::CLOSED;
     if (!$is_finalize && $revision['status'] != $status_accepted) {
         throw new ArcanistUsageException("Revision D{$revision_id} can not be closed. You can only close " . "revisions which have been 'accepted'.");
     }
     if ($revision) {
         if (!$is_finalize && $revision['authorPHID'] != $this->getUserPHID()) {
             $prompt = "You are not the author of revision D{$revision_id}, " . 'are you sure you want to close it?';
             if (!phutil_console_confirm($prompt)) {
                 throw new ArcanistUserAbortException();
             }
         }
         $actually_close = true;
         if ($is_finalize) {
             $project_info = $this->getProjectInfo();
             if (idx($project_info, 'tracked') || $revision['status'] != $status_accepted) {
                 $actually_close = false;
             }
         }
         if ($actually_close) {
             $revision_name = $revision['title'];
             echo "Closing revision D{$revision_id} '{$revision_name}'...\n";
             $conduit->callMethodSynchronous('differential.close', array('revisionID' => $revision_id));
         }
     }
     $status = $revision['status'];
     if ($status == $status_accepted || $status == $status_closed) {
         // If this has already been attached to commits, don't show the
         // "you can push this commit" message since we know it's been pushed
         // already.
         $is_finalized = empty($revision['commits']);
     } else {
         $is_finalized = false;
     }
     if (!$this->getArgument('quiet')) {
         if ($is_finalized) {
             $message = $this->getRepositoryAPI()->getFinalizedRevisionMessage();
             echo phutil_console_wrap($message) . "\n";
         } else {
             echo "Done.\n";
         }
     }
     return 0;
 }
 private final function doUpgradeSchemata($apply_only, $no_quickstart, $init_only)
 {
     $api = $this->getAPI();
     $applied = $this->getApi()->getAppliedPatches();
     if ($applied === null) {
         if ($this->dryRun) {
             echo pht("DRYRUN: Patch metadata storage doesn't exist yet, " . "it would be created.\n");
             return 0;
         }
         if ($apply_only) {
             throw new PhutilArgumentUsageException(pht('Storage has not been initialized yet, you must initialize ' . 'storage before selectively applying patches.'));
             return 1;
         }
         $legacy = $api->getLegacyPatches($this->patches);
         if ($legacy || $no_quickstart || $init_only) {
             // If we have legacy patches, we can't quickstart.
             $api->createDatabase('meta_data');
             $api->createTable('meta_data', 'patch_status', array('patch VARCHAR(255) NOT NULL PRIMARY KEY COLLATE utf8_general_ci', 'applied INT UNSIGNED NOT NULL'));
             foreach ($legacy as $patch) {
                 $api->markPatchApplied($patch);
             }
         } else {
             echo pht('Loading quickstart template...') . "\n";
             $root = dirname(phutil_get_library_root('phabricator'));
             $sql = $root . '/resources/sql/quickstart.sql';
             $api->applyPatchSQL($sql);
         }
     }
     if ($init_only) {
         echo pht('Storage initialized.') . "\n";
         return 0;
     }
     $applied = $api->getAppliedPatches();
     $applied = array_fuse($applied);
     $skip_mark = false;
     if ($apply_only) {
         if (isset($applied[$apply_only])) {
             unset($applied[$apply_only]);
             $skip_mark = true;
             if (!$this->force && !$this->dryRun) {
                 echo phutil_console_wrap(pht("Patch '%s' has already been applied. Are you sure you want " . "to apply it again? This may put your storage in a state " . "that the upgrade scripts can not automatically manage.", $apply_only));
                 if (!phutil_console_confirm(pht('Apply patch again?'))) {
                     echo pht('Cancelled.') . "\n";
                     return 1;
                 }
             }
         }
     }
     while (true) {
         $applied_something = false;
         foreach ($this->patches as $key => $patch) {
             if (isset($applied[$key])) {
                 unset($this->patches[$key]);
                 continue;
             }
             if ($apply_only && $apply_only != $key) {
                 unset($this->patches[$key]);
                 continue;
             }
             $can_apply = true;
             foreach ($patch->getAfter() as $after) {
                 if (empty($applied[$after])) {
                     if ($apply_only) {
                         echo pht("Unable to apply patch '%s' because it depends " . "on patch '%s', which has not been applied.\n", $apply_only, $after);
                         return 1;
                     }
                     $can_apply = false;
                     break;
                 }
             }
             if (!$can_apply) {
                 continue;
             }
             $applied_something = true;
             if ($this->dryRun) {
                 echo pht("DRYRUN: Would apply patch '%s'.", $key) . "\n";
             } else {
                 echo pht("Applying patch '%s'...", $key) . "\n";
                 $t_begin = microtime(true);
                 $api->applyPatch($patch);
                 $t_end = microtime(true);
                 if (!$skip_mark) {
                     $api->markPatchApplied($key, $t_end - $t_begin);
                 }
             }
             unset($this->patches[$key]);
             $applied[$key] = true;
         }
         if (!$applied_something) {
             if (count($this->patches)) {
                 throw new Exception(pht('Some patches could not be applied: %s', implode(', ', array_keys($this->patches))));
             } else {
                 if (!$this->dryRun && !$apply_only) {
                     echo pht("Storage is up to date. Use '%s' for details.", 'storage status') . "\n";
                 }
             }
             break;
         }
     }
 }
Esempio n. 26
0
echo "\n\n" . pht('ACCOUNT SUMMARY') . "\n\n";
$tpl = "%12s   %-30s   %-30s\n";
printf($tpl, null, pht('OLD VALUE'), pht('NEW VALUE'));
printf($tpl, pht('Username'), $original->getUsername(), $user->getUsername());
printf($tpl, pht('Real Name'), $original->getRealName(), $user->getRealName());
if ($is_new) {
    printf($tpl, pht('Email'), '', $create_email);
}
printf($tpl, pht('Password'), null, $changed_pass !== false ? pht('Updated') : pht('Unchanged'));
printf($tpl, pht('Bot'), $original->getIsSystemAgent() ? 'Y' : 'N', $set_system_agent ? 'Y' : 'N');
if ($verify_email) {
    printf($tpl, pht('Verify Email'), $verify_email->getIsVerified() ? 'Y' : 'N', $set_verified ? 'Y' : 'N');
}
printf($tpl, pht('Admin'), $original->getIsAdmin() ? 'Y' : 'N', $set_admin ? 'Y' : 'N');
echo "\n";
if (!phutil_console_confirm(pht('Save these changes?'), $default_no = false)) {
    echo pht('Cancelled.') . "\n";
    exit(1);
}
$user->openTransaction();
$editor = new PhabricatorUserEditor();
// TODO: This is wrong, but we have a chicken-and-egg problem when you use
// this script to create the first user.
$editor->setActor($user);
if ($is_new) {
    $email = id(new PhabricatorUserEmail())->setAddress($create_email)->setIsVerified(1);
    // Unconditionally approve new accounts created from the CLI.
    $user->setIsApproved(1);
    $editor->createNewUser($user, $email);
} else {
    if ($verify_email) {
Esempio n. 27
0
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
$root = dirname(dirname(dirname(__FILE__)));
require_once $root . '/scripts/__init_script__.php';
require_once $root . '/scripts/__init_env__.php';
phutil_require_module('phutil', 'console');
phutil_require_module('phutil', 'future/exec');
if (empty($argv[1])) {
    echo "usage: test_connection.php <repository_callsign>\n";
    exit(1);
}
echo phutil_console_wrap(phutil_console_format('This script will test that you have configured valid credentials for ' . 'access to a repository, so the Phabricator daemons can pull from it. ' . 'You should run this as the **same user you will run the daemons as**, ' . 'from the **same machine they will run from**. Doing this will help ' . 'detect various problems with your configuration, such as SSH issues.'));
list($whoami) = execx('whoami');
$whoami = trim($whoami);
$ok = phutil_console_confirm("Do you want to continue as '{$whoami}'?");
if (!$ok) {
    die(1);
}
$callsign = $argv[1];
echo "Loading '{$callsign}' repository...\n";
$repository = id(new PhabricatorRepository())->loadOneWhere('callsign = %s', $argv[1]);
if (!$repository) {
    throw new Exception("No such repository exists!");
}
$vcs = $repository->getVersionControlSystem();
PhutilServiceProfiler::installEchoListener();
echo "Trying to connect to the remote...\n";
switch ($vcs) {
    case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
        $err = $repository->passthruRemoteCommand('--limit 1 log %s', $repository->getRemoteURI());
 /**
  * Do the best we can to prevent PEBKAC and id10t issues.
  */
 private function sanityCheck(ArcanistBundle $bundle)
 {
     $repository_api = $this->getRepositoryAPI();
     // Require clean working copy
     $this->requireCleanWorkingCopy();
     // Check to see if the bundle's project id matches the working copy
     // project id
     $bundle_project_id = $bundle->getProjectID();
     $working_copy_project_id = $this->getWorkingCopy()->getProjectID();
     if (empty($bundle_project_id)) {
         // this means $source is SOURCE_PATCH || SOURCE_BUNDLE w/ $version = 0
         // they don't come with a project id so just do nothing
     } else {
         if ($bundle_project_id != $working_copy_project_id) {
             if ($working_copy_project_id) {
                 $issue = "This patch is for the '{$bundle_project_id}' project,  but the " . "working copy belongs to the '{$working_copy_project_id}' project.";
             } else {
                 $issue = "This patch is for the '{$bundle_project_id}' project, but the " . "working copy does not have an '.arcconfig' file to identify which " . "project it belongs to.";
             }
             $ok = phutil_console_confirm("{$issue} Still try to apply the patch?", $default_no = false);
             if (!$ok) {
                 throw new ArcanistUserAbortException();
             }
         }
     }
     // Check to see if the bundle's base revision matches the working copy
     // base revision
     if ($repository_api->supportsLocalCommits()) {
         $bundle_base_rev = $bundle->getBaseRevision();
         if (empty($bundle_base_rev)) {
             // this means $source is SOURCE_PATCH || SOURCE_BUNDLE w/ $version < 2
             // they don't have a base rev so just do nothing
             $commit_exists = true;
         } else {
             $commit_exists = $repository_api->hasLocalCommit($bundle_base_rev);
         }
         if (!$commit_exists) {
             // we have a problem...! lots of work because we need to ask
             // differential for revision information for these base revisions
             // to improve our error message.
             $bundle_base_rev_str = null;
             $source_base_rev = $repository_api->getWorkingCopyRevision();
             $source_base_rev_str = null;
             if ($repository_api instanceof ArcanistGitAPI) {
                 $hash_type = ArcanistDifferentialRevisionHash::HASH_GIT_COMMIT;
             } else {
                 if ($repository_api instanceof ArcanistMercurialAPI) {
                     $hash_type = ArcanistDifferentialRevisionHash::HASH_MERCURIAL_COMMIT;
                 } else {
                     $hash_type = null;
                 }
             }
             if ($hash_type) {
                 // 2 round trips because even though we could send off one query
                 // we wouldn't be able to tell which revisions were for which hash
                 $hash = array($hash_type, $bundle_base_rev);
                 $bundle_revision = $this->loadRevisionFromHash($hash);
                 $hash = array($hash_type, $source_base_rev);
                 $source_revision = $this->loadRevisionFromHash($hash);
                 if ($bundle_revision) {
                     $bundle_base_rev_str = $bundle_base_rev . ' \\ D' . $bundle_revision['id'];
                 }
                 if ($source_revision) {
                     $source_base_rev_str = $source_base_rev . ' \\ D' . $source_revision['id'];
                 }
             }
             $bundle_base_rev_str = nonempty($bundle_base_rev_str, $bundle_base_rev);
             $source_base_rev_str = nonempty($source_base_rev_str, $source_base_rev);
             $ok = phutil_console_confirm("This diff is against commit {$bundle_base_rev_str}, but the " . "commit is nowhere in the working copy. Try to apply it against " . "the current working copy state? ({$source_base_rev_str})", $default_no = false);
             if (!$ok) {
                 throw new ArcanistUserAbortException();
             }
         }
     }
     // TODO -- more sanity checks here
 }
Esempio n. 29
0
 private function removeAlias(array $aliases, $alias)
 {
     if (empty($aliases[$alias])) {
         echo tsprintf("%s\n", pht('No alias "%s" to remove.', $alias));
         return;
     }
     $command = implode(' ', $aliases[$alias]);
     if (self::isShellCommandAlias($command)) {
         echo tsprintf("%s\n", pht('"%s" is currently aliased to shell command "%s".', "arc {$alias}", substr($command, 1)));
     } else {
         echo tsprintf("%s\n", pht('"%s" is currently aliased to "%s".', "arc {$alias}", "arc {$command}"));
     }
     $ok = phutil_console_confirm(pht('Delete this alias?'));
     if (!$ok) {
         throw new ArcanistUserAbortException();
     }
     unset($aliases[$alias]);
     $this->writeAliases($aliases);
     echo tsprintf("%s\n", pht('Removed alias "%s".', "arc {$alias}"));
 }
Esempio n. 30
0
    spurious audit requests during import.

EOSYNOPSIS
);
$args->parseStandardArguments();
$args->parse(array(array('name' => 'more', 'wildcard' => true)));
$more = $args->getArg('more');
if (count($more) !== 1) {
    $args->printHelpAndExit();
}
$callsign = reset($more);
$repository = id(new PhabricatorRepository())->loadOneWhere('callsign = %s', $callsign);
if (!$repository) {
    throw new Exception("No repository exists with callsign '{$callsign}'!");
}
$ok = phutil_console_confirm('This will reset all open audit requests ("Audit Required" or "Concern ' . 'Raised") for commits in this repository to "Audit Not Required". This ' . 'operation destroys information and can not be undone! Are you sure ' . 'you want to proceed?');
if (!$ok) {
    echo "OK, aborting.\n";
    die(1);
}
echo "Loading commits...\n";
$all_commits = id(new PhabricatorRepositoryCommit())->loadAllWhere('repositoryID = %d', $repository->getID());
echo "Clearing audit requests...\n";
foreach ($all_commits as $commit) {
    $query = id(new PhabricatorAuditQuery())->withStatus(PhabricatorAuditQuery::STATUS_OPEN)->withCommitPHIDs(array($commit->getPHID()));
    $requests = $query->execute();
    echo "Clearing " . $commit->getPHID() . "... ";
    if (!$requests) {
        echo "nothing to do.\n";
        continue;
    } else {