diff --git a/src/applications/cache/spec/PhabricatorOpcodeCacheSpec.php b/src/applications/cache/spec/PhabricatorOpcodeCacheSpec.php index 37c02a437b..2a59d7e8aa 100644 --- a/src/applications/cache/spec/PhabricatorOpcodeCacheSpec.php +++ b/src/applications/cache/spec/PhabricatorOpcodeCacheSpec.php @@ -143,7 +143,7 @@ final class PhabricatorOpcodeCacheSpec extends PhabricatorCacheSpec { $this ->newIssue('extension.opcache.devmode') ->setShortName(pht('OPcache Config')) - ->setName(pht('OPCache Not Configured for Development')) + ->setName(pht('OPcache Not Configured for Development')) ->setSummary($summary) ->setMessage($message) ->addPHPConfig('opcache.validate_timestamps') diff --git a/src/applications/config/application/PhabricatorConfigApplication.php b/src/applications/config/application/PhabricatorConfigApplication.php index 9789b7de9f..e7540ad9de 100644 --- a/src/applications/config/application/PhabricatorConfigApplication.php +++ b/src/applications/config/application/PhabricatorConfigApplication.php @@ -15,7 +15,7 @@ final class PhabricatorConfigApplication extends PhabricatorApplication { } public function getTitleGlyph() { - return "\xE2\x98\xBA"; + return "\xE2\x9C\xA8"; } public function getApplicationGroup() { diff --git a/src/applications/config/view/PhabricatorSetupIssueView.php b/src/applications/config/view/PhabricatorSetupIssueView.php index 6fd75568ac..74bdc2d522 100644 --- a/src/applications/config/view/PhabricatorSetupIssueView.php +++ b/src/applications/config/view/PhabricatorSetupIssueView.php @@ -445,7 +445,7 @@ final class PhabricatorSetupIssueView extends AphrontView { 'p', array(), pht( - 'You can find more information about configuring OPCache in '. + 'You can find more information about configuring OPcache in '. 'the %s.', phutil_tag( 'a', @@ -453,7 +453,7 @@ final class PhabricatorSetupIssueView extends AphrontView { 'href' => 'http://php.net/manual/opcache.configuration.php', 'target' => '_blank', ), - pht('PHP OPCache Documentation')))); + pht('PHP OPcache Documentation')))); } $info[] = phutil_tag( diff --git a/src/applications/differential/application/PhabricatorDifferentialApplication.php b/src/applications/differential/application/PhabricatorDifferentialApplication.php index eaa4948eee..52b222301a 100644 --- a/src/applications/differential/application/PhabricatorDifferentialApplication.php +++ b/src/applications/differential/application/PhabricatorDifferentialApplication.php @@ -43,7 +43,10 @@ final class PhabricatorDifferentialApplication extends PhabricatorApplication { public function getRoutes() { return array( - '/D(?P[1-9]\d*)' => 'DifferentialRevisionViewController', + '/D(?P[1-9]\d*)' => array( + '' => 'DifferentialRevisionViewController', + '/(?Pnew)/' => 'DifferentialRevisionViewController', + ), '/differential/' => array( '(?:query/(?P[^/]+)/)?' => 'DifferentialRevisionListController', diff --git a/src/applications/differential/controller/DifferentialRevisionViewController.php b/src/applications/differential/controller/DifferentialRevisionViewController.php index cd71c62a1e..33440e535f 100644 --- a/src/applications/differential/controller/DifferentialRevisionViewController.php +++ b/src/applications/differential/controller/DifferentialRevisionViewController.php @@ -6,6 +6,7 @@ final class DifferentialRevisionViewController private $revisionID; private $changesetCount; private $hiddenChangesets; + private $warnings = array(); public function shouldAllowPublic() { return true; @@ -68,9 +69,17 @@ final class DifferentialRevisionViewController $revision->attachActiveDiff(last($diffs)); - $diff_vs = $request->getInt('vs'); - $target_id = $request->getInt('id'); - $target = idx($diffs, $target_id, end($diffs)); + $diff_vs = $this->getOldDiffID($revision, $diffs); + if ($diff_vs instanceof AphrontResponse) { + return $diff_vs; + } + + $target_id = $this->getNewDiffID($revision, $diffs); + if ($target_id instanceof AphrontResponse) { + return $target_id; + } + + $target = $diffs[$target_id]; $target_manual = $target; if (!$target_id) { @@ -81,10 +90,6 @@ final class DifferentialRevisionViewController } } - if (empty($diffs[$diff_vs])) { - $diff_vs = null; - } - $repository = null; $repository_phid = $target->getRepositoryPHID(); if ($repository_phid) { @@ -170,7 +175,7 @@ final class DifferentialRevisionViewController } $handles = $this->loadViewerHandles($object_phids); - $warnings = array(); + $warnings = $this->warnings; $request_uri = $request->getRequestURI(); @@ -1312,4 +1317,133 @@ final class DifferentialRevisionViewController ->setShowViewAll(true); } + private function getOldDiffID(DifferentialRevision $revision, array $diffs) { + assert_instances_of($diffs, 'DifferentialDiff'); + $request = $this->getRequest(); + + $diffs = mpull($diffs, null, 'getID'); + + $is_new = ($request->getURIData('filter') === 'new'); + $old_id = $request->getInt('vs'); + + // This is ambiguous, so just 404 rather than trying to figure out what + // the user expects. + if ($is_new && $old_id) { + return new Aphront404Response(); + } + + if ($is_new) { + $viewer = $this->getViewer(); + + $xactions = id(new DifferentialTransactionQuery()) + ->setViewer($viewer) + ->withObjectPHIDs(array($revision->getPHID())) + ->withAuthorPHIDs(array($viewer->getPHID())) + ->setOrder('newest') + ->setLimit(1) + ->execute(); + + if (!$xactions) { + $this->warnings[] = id(new PHUIInfoView()) + ->setTitle(pht('No Actions')) + ->setSeverity(PHUIInfoView::SEVERITY_WARNING) + ->appendChild( + pht( + 'Showing all changes because you have never taken an '. + 'action on this revision.')); + } else { + $xaction = head($xactions); + + // Find the transactions which updated this revision. We want to + // figure out which diff was active when you last took an action. + $updates = id(new DifferentialTransactionQuery()) + ->setViewer($viewer) + ->withObjectPHIDs(array($revision->getPHID())) + ->withTransactionTypes( + array( + DifferentialRevisionUpdateTransaction::TRANSACTIONTYPE, + )) + ->setOrder('oldest') + ->execute(); + + // Sort the diffs into two buckets: those older than your last action + // and those newer than your last action. + $older = array(); + $newer = array(); + foreach ($updates as $update) { + // If you updated the revision with "arc diff", try to count that + // update as "before your last action". + if ($update->getDateCreated() <= $xaction->getDateCreated()) { + $older[] = $update->getNewValue(); + } else { + $newer[] = $update->getNewValue(); + } + } + + if (!$newer) { + $this->warnings[] = id(new PHUIInfoView()) + ->setTitle(pht('No Recent Updates')) + ->setSeverity(PHUIInfoView::SEVERITY_WARNING) + ->appendChild( + pht( + 'Showing all changes because the diff for this revision '. + 'has not been updated since your last action.')); + } else { + $older = array_fuse($older); + + // Find the most recent diff from before the last action. + $old = null; + foreach ($diffs as $diff) { + if (!isset($older[$diff->getPHID()])) { + break; + } + + $old = $diff; + } + + // It's possible we may not find such a diff: transactions may have + // been removed from the database, for example. If we miss, just + // fail into some reasonable state since 404'ing would be perplexing. + if ($old) { + $this->warnings[] = id(new PHUIInfoView()) + ->setTitle(pht('New Changes Shown')) + ->setSeverity(PHUIInfoView::SEVERITY_NOTICE) + ->appendChild( + pht( + 'Showing changes since the last action you took on this '. + 'revision.')); + + $old_id = $old->getID(); + } + } + } + } + + if (isset($diffs[$old_id])) { + return $old_id; + } + + return null; + } + + private function getNewDiffID(DifferentialRevision $revision, array $diffs) { + assert_instances_of($diffs, 'DifferentialDiff'); + $request = $this->getRequest(); + + $diffs = mpull($diffs, null, 'getID'); + + $is_new = ($request->getURIData('filter') === 'new'); + $new_id = $request->getInt('id'); + + if ($is_new && $new_id) { + return new Aphront404Response(); + } + + if (isset($diffs[$new_id])) { + return $new_id; + } + + return (int)last_key($diffs); + } + } diff --git a/src/applications/differential/editor/DifferentialTransactionEditor.php b/src/applications/differential/editor/DifferentialTransactionEditor.php index 4a3e753292..f4dd3f9fe3 100644 --- a/src/applications/differential/editor/DifferentialTransactionEditor.php +++ b/src/applications/differential/editor/DifferentialTransactionEditor.php @@ -624,7 +624,9 @@ final class DifferentialTransactionEditor $body = new PhabricatorMetaMTAMailBody(); $body->setViewer($this->requireActor()); - $revision_uri = PhabricatorEnv::getProductionURI('/D'.$object->getID()); + $revision_uri = $object->getURI(); + $revision_uri = PhabricatorEnv::getProductionURI($revision_uri); + $new_uri = $revision_uri.'/new/'; $this->addHeadersAndCommentsToMailBody( $body, @@ -645,19 +647,6 @@ final class DifferentialTransactionEditor $this->appendInlineCommentsForMail($object, $inlines, $body); } - $changed_uri = $this->getChangedPriorToCommitURI(); - if ($changed_uri) { - $body->addLinkSection( - pht('CHANGED PRIOR TO COMMIT'), - $changed_uri); - } - - $this->addCustomFieldsToMailBody($body, $object, $xactions); - - $body->addLinkSection( - pht('REVISION DETAIL'), - $revision_uri); - $update_xaction = null; foreach ($xactions as $xaction) { switch ($xaction->getTransactionType()) { @@ -669,7 +658,28 @@ final class DifferentialTransactionEditor if ($update_xaction) { $diff = $this->requireDiff($update_xaction->getNewValue(), true); + } else { + $diff = null; + } + $changed_uri = $this->getChangedPriorToCommitURI(); + if ($changed_uri) { + $body->addLinkSection( + pht('CHANGED PRIOR TO COMMIT'), + $changed_uri); + } + + $this->addCustomFieldsToMailBody($body, $object, $xactions); + + if (!$this->getIsNewObject()) { + $body->addLinkSection(pht('CHANGES SINCE LAST ACTION'), $new_uri); + } + + $body->addLinkSection( + pht('REVISION DETAIL'), + $revision_uri); + + if ($update_xaction) { $body->addTextSection( pht('AFFECTED FILES'), $this->renderAffectedFilesForMail($diff)); diff --git a/src/applications/differential/lipsum/PhabricatorDifferentialRevisionTestDataGenerator.php b/src/applications/differential/lipsum/PhabricatorDifferentialRevisionTestDataGenerator.php index 2443fe9651..26632dff24 100644 --- a/src/applications/differential/lipsum/PhabricatorDifferentialRevisionTestDataGenerator.php +++ b/src/applications/differential/lipsum/PhabricatorDifferentialRevisionTestDataGenerator.php @@ -48,10 +48,12 @@ final class PhabricatorDifferentialRevisionTestDataGenerator public function generateDiff($author) { $paste_generator = new PhabricatorPasteTestDataGenerator(); - $languages = $paste_generator->supportedLanguages; - $lang = array_rand($languages); - $code = $paste_generator->generateContent($lang); - $altcode = $paste_generator->generateContent($lang); + $languages = $paste_generator->getSupportedLanguages(); + $language = array_rand($languages); + $spec = $languages[$language]; + + $code = $paste_generator->generateContent($spec); + $altcode = $paste_generator->generateContent($spec); $newcode = $this->randomlyModify($code, $altcode); $diff = id(new PhabricatorDifferenceEngine()) ->generateRawDiffFromFileContent($code, $newcode); diff --git a/src/applications/differential/view/DifferentialRevisionUpdateHistoryView.php b/src/applications/differential/view/DifferentialRevisionUpdateHistoryView.php index bdac860674..a77b320d82 100644 --- a/src/applications/differential/view/DifferentialRevisionUpdateHistoryView.php +++ b/src/applications/differential/view/DifferentialRevisionUpdateHistoryView.php @@ -307,7 +307,7 @@ final class DifferentialRevisionUpdateHistoryView extends AphrontView { $content = phabricator_form( $this->getUser(), array( - 'action' => '#toc', + 'action' => '/D'.$revision_id.'#toc', ), array( $table, diff --git a/src/applications/files/document/PhabricatorDocumentRef.php b/src/applications/files/document/PhabricatorDocumentRef.php index 38e4491615..036656c00e 100644 --- a/src/applications/files/document/PhabricatorDocumentRef.php +++ b/src/applications/files/document/PhabricatorDocumentRef.php @@ -119,11 +119,23 @@ final class PhabricatorDocumentRef } $snippet = $this->getSnippet(); - if (!preg_match('/^\s*[{[]/', $snippet)) { + + // If the file is longer than the snippet, we don't detect the content + // as JSON. We could use some kind of heuristic here if we wanted, but + // see PHI749 for a false positive. + if (strlen($snippet) < $this->getByteLength()) { return false; } - return phutil_is_utf8($snippet); + // If the snippet is the whole file, just check if the snippet is valid + // JSON. Note that `phutil_json_decode()` only accepts arrays and objects + // as JSON, so this won't misfire on files with content like "3". + try { + phutil_json_decode($snippet); + return true; + } catch (Exception $ex) { + return false; + } } public function getSnippet() { diff --git a/src/applications/files/storage/PhabricatorFile.php b/src/applications/files/storage/PhabricatorFile.php index b795678cd2..1517b4435b 100644 --- a/src/applications/files/storage/PhabricatorFile.php +++ b/src/applications/files/storage/PhabricatorFile.php @@ -492,12 +492,13 @@ final class PhabricatorFile extends PhabricatorFileDAO $this->setStorageFormat($format->getStorageFormatKey()); $this->setStorageProperties($properties); - list($identifier, $new_handle) = $this->writeToEngine( + list($identifier, $new_handle, $integrity_hash) = $this->writeToEngine( $engine, $data, $params); $this->setStorageHandle($new_handle); + $this->setIntegrityHash($integrity_hash); $this->save(); $this->deleteFileDataIfUnused( diff --git a/src/applications/macro/engine/PhabricatorMemeEngine.php b/src/applications/macro/engine/PhabricatorMemeEngine.php index 175aa2fb46..3e87a304c9 100644 --- a/src/applications/macro/engine/PhabricatorMemeEngine.php +++ b/src/applications/macro/engine/PhabricatorMemeEngine.php @@ -104,8 +104,8 @@ final class PhabricatorMemeEngine extends Phobject { private function newTransformHash() { $properties = array( 'kind' => 'meme', - 'above' => phutil_utf8_strtoupper($this->getAboveText()), - 'below' => phutil_utf8_strtoupper($this->getBelowText()), + 'above' => $this->getAboveText(), + 'below' => $this->getBelowText(), ); $properties = phutil_json_encode($properties); diff --git a/src/applications/paste/lipsum/PhabricatorPasteTestDataGenerator.php b/src/applications/paste/lipsum/PhabricatorPasteTestDataGenerator.php index 24ac718606..80dbc10ee0 100644 --- a/src/applications/paste/lipsum/PhabricatorPasteTestDataGenerator.php +++ b/src/applications/paste/lipsum/PhabricatorPasteTestDataGenerator.php @@ -22,9 +22,11 @@ final class PhabricatorPasteTestDataGenerator PhabricatorPasteTitleTransaction::TRANSACTIONTYPE, $name); - $xactions[] = $this->newTransaction( - PhabricatorPasteLanguageTransaction::TRANSACTIONTYPE, - $language); + if (strlen($language) > 0) { + $xactions[] = $this->newTransaction( + PhabricatorPasteLanguageTransaction::TRANSACTIONTYPE, + $language); + } $xactions[] = $this->newTransaction( PhabricatorPasteContentTransaction::TRANSACTIONTYPE, @@ -43,17 +45,29 @@ final class PhabricatorPasteTestDataGenerator return new PhabricatorPasteTransaction(); } - private function newPasteContent() { - $languages = array( - 'txt' => array(), - 'php' => array( - 'content' => 'PhutilPHPCodeSnippetContextFreeGrammar', - ), - 'java' => array( - 'content' => 'PhutilJavaCodeSnippetContextFreeGrammar', - ), - ); + public function getSupportedLanguages() { + return array( + 'php' => array( + 'content' => 'PhutilPHPCodeSnippetContextFreeGrammar', + ), + 'java' => array( + 'content' => 'PhutilJavaCodeSnippetContextFreeGrammar', + ), + ); + } + public function generateContent($spec) { + $content_generator = idx($spec, 'content'); + if (!$content_generator) { + $content_generator = 'PhutilLipsumContextFreeGrammar'; + } + + return newv($content_generator, array()) + ->generateSeveral($this->roll(4, 12, 10)); + } + + private function newPasteContent() { + $languages = $this->getSupportedLanguages(); $language = array_rand($languages); $spec = $languages[$language]; @@ -62,16 +76,10 @@ final class PhabricatorPasteTestDataGenerator $title_generator = 'PhabricatorPasteFilenameContextFreeGrammar'; } - $content_generator = idx($spec, 'content'); - if (!$content_generator) { - $content_generator = 'PhutilLipsumContextFreeGrammar'; - } - $title = newv($title_generator, array()) ->generate(); - $content = newv($content_generator, array()) - ->generateSeveral($this->roll(4, 12, 10)); + $content = $this->generateContent($spec); // Usually add the language as a suffix. if ($this->roll(1, 20) > 2) { diff --git a/src/applications/project/query/PhabricatorProjectSearchEngine.php b/src/applications/project/query/PhabricatorProjectSearchEngine.php index e38532c419..02e795395a 100644 --- a/src/applications/project/query/PhabricatorProjectSearchEngine.php +++ b/src/applications/project/query/PhabricatorProjectSearchEngine.php @@ -22,7 +22,13 @@ final class PhabricatorProjectSearchEngine return array( id(new PhabricatorSearchTextField()) ->setLabel(pht('Name')) - ->setKey('name'), + ->setKey('name') + ->setDescription( + pht( + '(Deprecated.) Search for projects with a given name or '. + 'hashtag using tokenizer/datasource query matching rules. This '. + 'is deprecated in favor of the more powerful "query" '. + 'constraint.')), id(new PhabricatorSearchStringListField()) ->setLabel(pht('Slugs')) ->setIsHidden(true) diff --git a/src/applications/search/engineextension/PhabricatorFerretSearchEngineExtension.php b/src/applications/search/engineextension/PhabricatorFerretSearchEngineExtension.php index 65822b0a32..55b7c2225a 100644 --- a/src/applications/search/engineextension/PhabricatorFerretSearchEngineExtension.php +++ b/src/applications/search/engineextension/PhabricatorFerretSearchEngineExtension.php @@ -57,7 +57,10 @@ final class PhabricatorFerretSearchEngineExtension $fields[] = id(new PhabricatorSearchTextField()) ->setKey('query') ->setLabel(pht('Query')) - ->setDescription(pht('Fulltext search.')); + ->setDescription( + pht( + 'Find objects matching a fulltext search query. See '. + '"Search User Guide" in the documentation for details.')); return $fields; } diff --git a/src/applications/search/query/PhabricatorFulltextToken.php b/src/applications/search/query/PhabricatorFulltextToken.php index 8dc2cee3ca..e99c2151c7 100644 --- a/src/applications/search/query/PhabricatorFulltextToken.php +++ b/src/applications/search/query/PhabricatorFulltextToken.php @@ -60,6 +60,10 @@ final class PhabricatorFulltextToken extends Phobject { $tip = pht('Substring Search'); $shade = PHUITagView::COLOR_VIOLET; break; + case PhutilSearchQueryCompiler::OPERATOR_EXACT: + $tip = pht('Exact Search'); + $shade = PHUITagView::COLOR_GREEN; + break; default: $shade = PHUITagView::COLOR_BLUE; break; diff --git a/src/applications/search/view/PhabricatorSearchResultView.php b/src/applications/search/view/PhabricatorSearchResultView.php index 8819f41869..6c527733e8 100644 --- a/src/applications/search/view/PhabricatorSearchResultView.php +++ b/src/applications/search/view/PhabricatorSearchResultView.php @@ -84,6 +84,7 @@ final class PhabricatorSearchResultView extends AphrontView { switch ($operator) { case PhutilSearchQueryCompiler::OPERATOR_SUBSTRING: + case PhutilSearchQueryCompiler::OPERATOR_EXACT: $patterns[] = '(('.preg_quote($value).'))ui'; break; case PhutilSearchQueryCompiler::OPERATOR_AND: diff --git a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php index f76f66df66..7e98ebb364 100644 --- a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php +++ b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php @@ -3599,6 +3599,7 @@ abstract class PhabricatorApplicationTransactionEditor ->setContinueOnMissingFields(true) ->setParentMessageID($this->getParentMessageID()) ->setIsInverseEdgeEditor(true) + ->setIsSilent($this->getIsSilent()) ->setActor($this->requireActor()) ->setActingAsPHID($this->getActingAsPHID()) ->setContentSource($this->getContentSource()); diff --git a/src/docs/user/userguide/search.diviner b/src/docs/user/userguide/search.diviner index d1c6182128..f1b32e7dc7 100644 --- a/src/docs/user/userguide/search.diviner +++ b/src/docs/user/userguide/search.diviner @@ -138,6 +138,7 @@ some special syntax. These features are supported: - Field search with `title:platypus`. - Filtering out matches with `-platypus`. - Quoted terms with `"platypus attorney"`. + - Matching entire fields with `=platypus`. - Combining features with `title:~"platypus attorney"`. See below for more detail. @@ -173,3 +174,11 @@ or `title:"platypus attorney"`. These scopes are also supported: **Filtering Matches**: You can remove documents which match certain terms from the result set with `-`. For example: `platypus -mammal`. Documents which match negated terms will be filtered out of the result set. + +**Matching Entire Fields**: If you know the exact name of an object and want +to find only that object, you can use the `=` operator. A query like +`title:"warp drive"` will find a document titled "Warp Drive", but will also +find documents with longer titles, like "Not a Warp Drive". The `=` operator +requires that the entire field match the query exactly, so //only// documents +exactly titled "Warp Drive" will be matched by the query (but note that the +query is still case insensitive). diff --git a/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php b/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php index 5193b14975..1784a8ce17 100644 --- a/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php +++ b/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php @@ -1918,6 +1918,7 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery $op_sub = PhutilSearchQueryCompiler::OPERATOR_SUBSTRING; $op_not = PhutilSearchQueryCompiler::OPERATOR_NOT; + $op_exact = PhutilSearchQueryCompiler::OPERATOR_EXACT; $where = array(); $current_function = 'all'; @@ -1941,6 +1942,25 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery $is_substring = false; } + // If we're doing exact search, just test the raw corpus. + $is_exact = ($raw_token->getOperator() == $op_exact); + if ($is_exact) { + if ($is_not) { + $where[] = qsprintf( + $conn, + '(%T.rawCorpus != %s)', + $table_alias, + $value); + } else { + $where[] = qsprintf( + $conn, + '(%T.rawCorpus = %s)', + $table_alias, + $value); + } + continue; + } + // If we're doing substring search, we just match against the raw corpus // and we're done. if ($is_substring) { diff --git a/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementDestroyWorkflow.php b/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementDestroyWorkflow.php index aacad288bc..7d0946c8c3 100644 --- a/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementDestroyWorkflow.php +++ b/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementDestroyWorkflow.php @@ -24,21 +24,33 @@ final class PhabricatorStorageManagementDestroyWorkflow $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 ($args->getArg('unittest-fixtures')) { + $console->writeOut( + phutil_console_wrap( + pht( + 'Are you completely sure you really want to destroy all unit '. + 'test fixure data? This operation can not be undone.'))); + if (!phutil_console_confirm(pht('Destroy all unit test data?'))) { + $console->writeOut("%s\n", pht('Cancelled.')); + exit(1); + } + } else { + $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('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); + if (!phutil_console_confirm(pht('Really destroy all data forever?'))) { + $console->writeOut("%s\n", pht('Cancelled.')); + exit(1); + } } }