public function establishLiveConnection($mode)
 {
     $conf_provider = PhabricatorEnv::getEnvConfig('mysql.configuration_provider', 'DatabaseConfigurationProvider');
     PhutilSymbolLoader::loadClass($conf_provider);
     $conf = newv($conf_provider, array($this, $mode));
     return new AphrontMySQLDatabaseConnection(array('user' => $conf->getUser(), 'pass' => $conf->getPassword(), 'host' => $conf->getHost(), 'database' => $conf->getDatabase()));
 }
 public final function buildController()
 {
     $map = $this->getURIMap();
     $mapper = new AphrontURIMapper($map);
     $request = $this->getRequest();
     $path = $request->getPath();
     list($controller_class, $uri_data) = $mapper->mapPath($path);
     if (!$controller_class) {
         if (!preg_match('@/$@', $path)) {
             // If we failed to match anything but don't have a trailing slash, try
             // to add a trailing slash and issue a redirect if that resolves.
             list($controller_class, $uri_data) = $mapper->mapPath($path . '/');
             // NOTE: For POST, just 404 instead of redirecting, since the redirect
             // will be a GET without parameters.
             if ($controller_class && !$request->isHTTPPost()) {
                 $uri = $request->getRequestURI()->setPath($path . '/');
                 return $this->buildRedirectController($uri);
             }
         }
         return $this->build404Controller();
     }
     PhutilSymbolLoader::loadClass($controller_class);
     $controller = newv($controller_class, array($request));
     return array($controller, $uri_data);
 }
 protected final function updateCommitData($author, $message)
 {
     $commit = $this->commit;
     $data = id(new PhabricatorRepositoryCommitData())->loadOneWhere('commitID = %d', $commit->getID());
     if (!$data) {
         $data = new PhabricatorRepositoryCommitData();
     }
     $data->setCommitID($commit->getID());
     $data->setAuthorName($author);
     $data->setCommitMessage($message);
     $repository = $this->repository;
     $detail_parser = $repository->getDetail('detail-parser', 'PhabricatorRepositoryDefaultCommitMessageDetailParser');
     if ($detail_parser) {
         PhutilSymbolLoader::loadClass($detail_parser);
         $parser_obj = newv($detail_parser, array($commit, $data));
         $parser_obj->parseCommitDetails();
     }
     $data->save();
     $revision_id = $data->getCommitDetail('differential.revisionID');
     if ($revision_id) {
         $revision = id(new DifferentialRevision())->load($revision_id);
         if ($revision) {
             queryfx($revision->establishConnection('w'), 'INSERT IGNORE INTO %T (revisionID, commitPHID) VALUES (%d, %s)', DifferentialRevision::TABLE_COMMIT, $revision->getID(), $commit->getPHID());
             if ($revision->getStatus() != DifferentialRevisionStatus::COMMITTED) {
                 $editor = new DifferentialCommentEditor($revision, $revision->getAuthorPHID(), DifferentialAction::ACTION_COMMIT);
                 $editor->save();
             }
         }
     }
 }
 public static function getConfiguration()
 {
     // Get DB info. Note that we are using a dummy PhabricatorUser object in
     // creating the DatabaseConfigurationProvider, which is not used at all.
     $conf_provider = PhabricatorEnv::getEnvConfig('mysql.configuration_provider', 'DatabaseConfigurationProvider');
     PhutilSymbolLoader::loadClass($conf_provider);
     $conf = newv($conf_provider, array(new PhabricatorUser(), 'r'));
     return $conf;
 }
 protected final function updateCommitData($author, $message)
 {
     $commit = $this->commit;
     $data = id(new PhabricatorRepositoryCommitData())->loadOneWhere('commitID = %d', $commit->getID());
     if (!$data) {
         $data = new PhabricatorRepositoryCommitData();
     }
     $data->setCommitID($commit->getID());
     $data->setAuthorName($author);
     $data->setCommitMessage($message);
     $repository = $this->repository;
     $detail_parser = $repository->getDetail('detail-parser', 'PhabricatorRepositoryDefaultCommitMessageDetailParser');
     if ($detail_parser) {
         PhutilSymbolLoader::loadClass($detail_parser);
         $parser_obj = newv($detail_parser, array($commit, $data));
         $parser_obj->parseCommitDetails();
     }
     $data->save();
     $conn_w = id(new DifferentialRevision())->establishConnection('w');
     // NOTE: The `differential_commit` table has a unique ID on `commitPHID`,
     // preventing more than one revision from being associated with a commit.
     // Generally this is good and desirable, but with the advent of hash
     // tracking we may end up in a situation where we match several different
     // revisions. We just kind of ignore this and pick one, we might want to
     // revisit this and do something differently. (If we match several revisions
     // someone probably did something very silly, though.)
     $revision_id = $data->getCommitDetail('differential.revisionID');
     if (!$revision_id) {
         $hashes = $this->getCommitHashes($this->repository, $this->commit);
         if ($hashes) {
             $query = new DifferentialRevisionQuery();
             $query->withCommitHashes($hashes);
             $revisions = $query->execute();
             if (!empty($revisions)) {
                 $revision = $this->identifyBestRevision($revisions);
                 $revision_id = $revision->getID();
             }
         }
     }
     if ($revision_id) {
         $revision = id(new DifferentialRevision())->load($revision_id);
         if ($revision) {
             queryfx($conn_w, 'INSERT IGNORE INTO %T (revisionID, commitPHID) VALUES (%d, %s)', DifferentialRevision::TABLE_COMMIT, $revision->getID(), $commit->getPHID());
             if ($revision->getStatus() != DifferentialRevisionStatus::COMMITTED) {
                 $message = null;
                 $committer = $data->getCommitDetail('authorPHID');
                 if (!$committer) {
                     $committer = $revision->getAuthorPHID();
                     $message = 'Change committed by ' . $data->getAuthorName() . '.';
                 }
                 $editor = new DifferentialCommentEditor($revision, $committer, DifferentialAction::ACTION_COMMIT);
                 $editor->setMessage($message)->save();
             }
         }
     }
 }
 public static function stopProfiler()
 {
     if (self::$profilerStarted) {
         $data = xhprof_disable();
         $data = serialize($data);
         $file_class = 'PhabricatorFile';
         PhutilSymbolLoader::loadClass($file_class);
         $file = call_user_func(array($file_class, 'newFromFileData'), $data, array('mime-type' => 'application/xhprof', 'name' => 'profile.xhprof'));
         return $file->getPHID();
     } else {
         return null;
     }
 }
 public static function newProvider($which)
 {
     switch ($which) {
         case self::PROVIDER_FACEBOOK:
             $class = 'PhabricatorOAuthProviderFacebook';
             break;
         case self::PROVIDER_GITHUB:
             $class = 'PhabricatorOAuthProviderGithub';
             break;
         default:
             throw new Exception('Unknown OAuth provider.');
     }
     PhutilSymbolLoader::loadClass($class);
     return newv($class, array());
 }
 public static function stopProfiler()
 {
     if (self::$profilerStarted) {
         $data = xhprof_disable();
         $data = serialize($data);
         $file_class = 'PhabricatorFile';
         PhutilSymbolLoader::loadClass($file_class);
         // Since these happen on GET we can't do guarded writes.
         $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
         $file = call_user_func(array($file_class, 'newFromFileData'), $data, array('mime-type' => 'application/xhprof', 'name' => 'profile.xhprof'));
         return $file->getPHID();
     } else {
         return null;
     }
 }
 public static final function newFromDiffusionRequest(DiffusionRequest $request)
 {
     $repository = $request->getRepository();
     switch ($repository->getVersionControlSystem()) {
         case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
             $class = 'DiffusionGitBranchQuery';
             break;
         default:
             throw new Exception("Unsupported VCS!");
     }
     PhutilSymbolLoader::loadClass($class);
     $query = new $class();
     $query->request = $request;
     return $query;
 }
 protected function execute(ConduitAPIRequest $request)
 {
     $task_phid = $request->getValue('task_phid');
     $orig_rev_phids = $request->getValue('orig_rev_phids');
     if (empty($orig_rev_phids)) {
         $orig_rev_phids = array();
     }
     $new_rev_phids = $request->getValue('new_rev_phids');
     if (empty($new_rev_phids)) {
         $new_rev_phids = array();
     }
     $task_class = PhabricatorEnv::getEnvConfig('differential.attach-task-class');
     if (!$task_class) {
         throw new ConduitException('ERR_NO_TASKATTACHER_DEFINED');
     }
     PhutilSymbolLoader::loadClass($task_class);
     $task_attacher = newv($task_class, array());
     $task_attacher->updateTaskRevisionAssoc($task_phid, $orig_rev_phids, $new_rev_phids);
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $methods = $this->getAllMethods();
     if (empty($methods[$this->method])) {
         $this->method = key($methods);
     }
     $method_class = $methods[$this->method];
     PhutilSymbolLoader::loadClass($method_class);
     $method_object = newv($method_class, array());
     $error_description = array();
     $error_types = $method_object->defineErrorTypes();
     if ($error_types) {
         $error_description[] = '<ul>';
         foreach ($error_types as $error => $meaning) {
             $error_description[] = '<li>' . '<strong>' . phutil_escape_html($error) . ':</strong> ' . phutil_escape_html($meaning) . '</li>';
         }
         $error_description[] = '</ul>';
         $error_description = implode("\n", $error_description);
     } else {
         $error_description = "This method does not raise any specific errors.";
     }
     $form = new AphrontFormView();
     $form->setUser($request->getUser())->setAction('/api/' . $this->method)->appendChild(id(new AphrontFormStaticControl())->setLabel('Description')->setValue($method_object->getMethodDescription()))->appendChild(id(new AphrontFormStaticControl())->setLabel('Returns')->setValue($method_object->defineReturnType()))->appendChild(id(new AphrontFormMarkupControl())->setLabel('Errors')->setValue($error_description))->appendChild('<p class="aphront-form-instructions">Enter parameters using ' . '<strong>JSON</strong>. For instance, to enter a list, type: ' . '<tt>["apple", "banana", "cherry"]</tt>');
     $params = $method_object->defineParamTypes();
     foreach ($params as $param => $desc) {
         $form->appendChild(id(new AphrontFormTextControl())->setLabel($param)->setName("params[{$param}]")->setCaption(phutil_escape_html($desc)));
     }
     $form->appendChild(id(new AphrontFormSelectControl())->setLabel('Output Format')->setName('output')->setOptions(array('human' => 'Human Readable', 'json' => 'JSON')))->appendChild(id(new AphrontFormSubmitControl())->setValue('Call Method'));
     $panel = new AphrontPanelView();
     $panel->setHeader('Conduit API: ' . phutil_escape_html($this->method));
     $panel->appendChild($form);
     $panel->setWidth(AphrontPanelView::WIDTH_WIDE);
     $view = new AphrontSideNavView();
     foreach ($this->buildNavItems() as $item) {
         $view->addNavItem($item);
     }
     $view->appendChild($panel);
     return $this->buildStandardPageResponse(array($view), array('title' => 'Conduit Console', 'tab' => 'console'));
 }
Пример #12
0
 public static final function newFromDiffusionRequest(DiffusionRequest $request)
 {
     $repository = $request->getRepository();
     switch ($repository->getVersionControlSystem()) {
         case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
             // TODO: Verify local-path?
             $class = 'DiffusionGitBrowseQuery';
             break;
         case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
             $class = 'DiffusionMercurialBrowseQuery';
             break;
         case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
             $class = 'DiffusionSvnBrowseQuery';
             break;
         default:
             throw new Exception("Unsupported VCS!");
     }
     PhutilSymbolLoader::loadClass($class);
     $query = new $class();
     $query->request = $request;
     return $query;
 }
 public final function buildController()
 {
     $map = $this->getURIMap();
     $mapper = new AphrontURIMapper($map);
     $request = $this->getRequest();
     $path = $request->getPath();
     list($controller_class, $uri_data) = $mapper->mapPath($path);
     if (!$controller_class) {
         if (!preg_match('@/$@', $path)) {
             // If we failed to match anything but don't have a trailing slash, try
             // to add a trailing slash and issue a redirect if that resolves.
             list($controller_class, $uri_data) = $mapper->mapPath($path . '/');
             if ($controller_class) {
                 return $this->buildRedirectController($path . '/');
             }
         }
         return $this->build404Controller();
     }
     PhutilSymbolLoader::loadClass($controller_class);
     $controller = newv($controller_class, array($request));
     return array($controller, $uri_data);
 }
 public function processRequest()
 {
     $current_user = $this->getRequest()->getUser();
     $provider = $this->provider;
     if (!$provider->isProviderEnabled()) {
         return new Aphront400Response();
     }
     $provider_name = $provider->getProviderName();
     $provider_key = $provider->getProviderKey();
     $request = $this->getRequest();
     if ($request->getStr('error')) {
         $error_view = id(new PhabricatorOAuthFailureView())->setRequest($request);
         return $this->buildErrorResponse($error_view);
     }
     $error_response = $this->retrieveAccessToken($provider);
     if ($error_response) {
         return $error_response;
     }
     $userinfo_uri = new PhutilURI($provider->getUserInfoURI());
     $userinfo_uri->setQueryParams(array('access_token' => $this->accessToken));
     $user_json = @file_get_contents($userinfo_uri);
     $user_data = json_decode($user_json, true);
     $provider->setUserData($user_data);
     $provider->setAccessToken($this->accessToken);
     $user_id = $provider->retrieveUserID();
     $provider_key = $provider->getProviderKey();
     $oauth_info = $this->retrieveOAuthInfo($provider);
     if ($current_user->getPHID()) {
         if ($oauth_info->getID()) {
             if ($oauth_info->getUserID() != $current_user->getID()) {
                 $dialog = new AphrontDialogView();
                 $dialog->setUser($current_user);
                 $dialog->setTitle('Already Linked to Another Account');
                 $dialog->appendChild('<p>The ' . $provider_name . ' account you just authorized ' . 'is already linked to another Phabricator account. Before you can ' . 'associate your ' . $provider_name . ' account with this Phabriactor ' . 'account, you must unlink it from the Phabricator account it is ' . 'currently linked to.</p>');
                 $dialog->addCancelButton('/settings/page/' . $provider_key . '/');
                 return id(new AphrontDialogResponse())->setDialog($dialog);
             } else {
                 return id(new AphrontRedirectResponse())->setURI('/settings/page/' . $provider_key . '/');
             }
         }
         $existing_oauth = id(new PhabricatorUserOAuthInfo())->loadOneWhere('userID = %d AND oauthProvider = %s', $current_user->getID(), $provider_key);
         if ($existing_oauth) {
             $dialog = new AphrontDialogView();
             $dialog->setUser($current_user);
             $dialog->setTitle('Already Linked to an Account From This Provider');
             $dialog->appendChild('<p>The account you are logged in with is already linked to a ' . $provider_name . ' account. Before you can link it to a different ' . $provider_name . ' account, you must unlink the old account.</p>');
             $dialog->addCancelButton('/settings/page/' . $provider_key . '/');
             return id(new AphrontDialogResponse())->setDialog($dialog);
         }
         if (!$request->isDialogFormPost()) {
             $dialog = new AphrontDialogView();
             $dialog->setUser($current_user);
             $dialog->setTitle('Link ' . $provider_name . ' Account');
             $dialog->appendChild('<p>Link your ' . $provider_name . ' account to your Phabricator ' . 'account?</p>');
             $dialog->addHiddenInput('token', $provider->getAccessToken());
             $dialog->addHiddenInput('expires', $oauth_info->getTokenExpires());
             $dialog->addHiddenInput('state', $this->oauthState);
             $dialog->addSubmitButton('Link Accounts');
             $dialog->addCancelButton('/settings/page/' . $provider_key . '/');
             return id(new AphrontDialogResponse())->setDialog($dialog);
         }
         $oauth_info->setUserID($current_user->getID());
         $this->saveOAuthInfo($oauth_info);
         return id(new AphrontRedirectResponse())->setURI('/settings/page/' . $provider_key . '/');
     }
     $next_uri = $request->getCookie('next_uri', '/');
     // Login with known auth.
     if ($oauth_info->getID()) {
         $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
         $known_user = id(new PhabricatorUser())->load($oauth_info->getUserID());
         $request->getApplicationConfiguration()->willAuthenticateUserWithOAuth($known_user, $oauth_info, $provider);
         $session_key = $known_user->establishSession('web');
         $this->saveOAuthInfo($oauth_info);
         $request->setCookie('phusr', $known_user->getUsername());
         $request->setCookie('phsid', $session_key);
         $request->clearCookie('next_uri');
         return id(new AphrontRedirectResponse())->setURI($next_uri);
     }
     $oauth_email = $provider->retrieveUserEmail();
     if ($oauth_email) {
         $known_email = id(new PhabricatorUser())->loadOneWhere('email = %s', $oauth_email);
         if ($known_email) {
             $dialog = new AphrontDialogView();
             $dialog->setUser($current_user);
             $dialog->setTitle('Already Linked to Another Account');
             $dialog->appendChild('<p>The ' . $provider_name . ' account you just authorized has an ' . 'email address which is already in use by another Phabricator ' . 'account. To link the accounts, log in to your Phabricator ' . 'account and then go to Settings.</p>');
             $dialog->addCancelButton('/login/');
             return id(new AphrontDialogResponse())->setDialog($dialog);
         }
     }
     if (!$provider->isProviderRegistrationEnabled()) {
         $dialog = new AphrontDialogView();
         $dialog->setUser($current_user);
         $dialog->setTitle('No Account Registration With ' . $provider_name);
         $dialog->appendChild('<p>You can not register a new account using ' . $provider_name . '; ' . 'you can only use your ' . $provider_name . ' account to log into an ' . 'existing Phabricator account which you have registered through ' . 'other means.</p>');
         $dialog->addCancelButton('/login/');
         return id(new AphrontDialogResponse())->setDialog($dialog);
     }
     $class = PhabricatorEnv::getEnvConfig('controller.oauth-registration');
     PhutilSymbolLoader::loadClass($class);
     $controller = newv($class, array($this->getRequest()));
     $controller->setOAuthProvider($provider);
     $controller->setOAuthInfo($oauth_info);
     $controller->setOAuthState($this->oauthState);
     return $this->delegateToController($controller);
 }
 private function updateTasks()
 {
     if ($this->tasks) {
         $task_class = PhabricatorEnv::getEnvConfig('differential.attach-task-class');
         if ($task_class) {
             PhutilSymbolLoader::loadClass($task_class);
             $task_attacher = newv($task_class, array());
             $ret = $task_attacher->attachTasksToRevision($this->actorPHID, $this->revision, $this->tasks);
         }
     }
 }
Пример #16
0
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * 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';
phutil_require_module('phutil', 'symbols');
PhutilSymbolLoader::loadClass('PhabricatorRepository');
PhutilSymbolLoader::loadClass('PhabricatorRepositoryCommit');
$commit = new PhabricatorRepositoryCommit();
$conn_w = id(new PhabricatorRepository())->establishConnection('w');
$sizes = queryfx_all($conn_w, 'SELECT repositoryID, count(*) N FROM %T GROUP BY repositoryID', $commit->getTableName());
$sizes = ipull($sizes, 'N', 'repositoryID');
$maxes = queryfx_all($conn_w, 'SELECT repositoryID, max(epoch) maxEpoch FROM %T GROUP BY repositoryID', $commit->getTableName());
$maxes = ipull($maxes, 'maxEpoch', 'repositoryID');
$repository_ids = array_keys($sizes + $maxes);
echo "Updating " . count($repository_ids) . " repositories";
foreach ($repository_ids as $repository_id) {
    $last_commit = queryfx_one($conn_w, 'SELECT id FROM %T WHERE repositoryID = %d AND epoch = %d LIMIT 1', $commit->getTableName(), $repository_id, idx($maxes, $repository_id, 0));
    if ($last_commit) {
        $last_commit = $last_commit['id'];
    } else {
        $last_commit = 0;
    }
 public function buildDefaultMailer()
 {
     $class_name = PhabricatorEnv::getEnvConfig('metamta.mail-adapter');
     PhutilSymbolLoader::loadClass($class_name);
     return newv($class_name, array());
 }
Пример #18
0
        phutil_load_library($library);
    }
}
phutil_require_module('phutil', 'symbols');
PhutilErrorHandler::initialize();
function phutil_daemon_error_listener($event, $value, array $metadata)
{
    $message = idx($metadata, 'default_message');
    if ($message) {
        file_put_contents('php://stderr', $message);
    }
}
if ($echo_to_stderr) {
    // If the caller has used "--log" to redirect the error log to a file, PHP
    // won't output it to stderr so the overseer can't capture it and won't
    // be able to send it to the web console. Install a listener which just echoes
    // errors to stderr, so we always get all the messages in the log and over
    // stdio, so they'll show up in the web console.
    PhutilErrorHandler::setErrorListener('phutil_daemon_error_listener');
}
$daemon = $argv[1];
$argv = array_slice($argv, 2);
PhutilSymbolLoader::loadClass($daemon);
$daemon = newv($daemon, array($argv));
if ($trace_mode) {
    $daemon->setTraceMode();
}
if ($trace_memory) {
    $daemon->setTraceMemory();
}
$daemon->execute();
Пример #19
0
 public static function newPlugin($plugin)
 {
     $class = 'DarkConsole' . $plugin . 'Plugin';
     PhutilSymbolLoader::loadClass($class);
     return newv($class, array());
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     $viewer_is_anonymous = !$user->isLoggedIn();
     $revision = id(new DifferentialRevision())->load($this->revisionID);
     if (!$revision) {
         return new Aphront404Response();
     }
     $revision->loadRelationships();
     $diffs = $revision->loadDiffs();
     if (!$diffs) {
         throw new Exception("This revision has no diffs. Something has gone quite wrong.");
     }
     $diff_vs = $request->getInt('vs');
     $target = end($diffs);
     $target_id = $request->getInt('id');
     if ($target_id) {
         if (isset($diffs[$target_id])) {
             $target = $diffs[$target_id];
         }
     }
     $diffs = mpull($diffs, null, 'getID');
     if (empty($diffs[$diff_vs])) {
         $diff_vs = null;
     }
     list($aux_fields, $props) = $this->loadAuxiliaryFieldsAndProperties($revision, $target, array('local:commits', 'arc:unit'));
     list($changesets, $vs_map, $rendering_references) = $this->loadChangesetsAndVsMap($diffs, $diff_vs, $target);
     $comments = $revision->loadComments();
     $comments = array_merge($this->getImplicitComments($revision), $comments);
     $all_changesets = $changesets;
     $inlines = $this->loadInlineComments($comments, $all_changesets);
     $object_phids = array_merge($revision->getReviewers(), $revision->getCCPHIDs(), $revision->loadCommitPHIDs(), array($revision->getAuthorPHID(), $user->getPHID()), mpull($comments, 'getAuthorPHID'));
     foreach ($comments as $comment) {
         $metadata = $comment->getMetadata();
         $added_reviewers = idx($metadata, DifferentialComment::METADATA_ADDED_REVIEWERS);
         if ($added_reviewers) {
             foreach ($added_reviewers as $phid) {
                 $object_phids[] = $phid;
             }
         }
         $added_ccs = idx($metadata, DifferentialComment::METADATA_ADDED_CCS);
         if ($added_ccs) {
             foreach ($added_ccs as $phid) {
                 $object_phids[] = $phid;
             }
         }
     }
     foreach ($revision->getAttached() as $type => $phids) {
         foreach ($phids as $phid => $info) {
             $object_phids[] = $phid;
         }
     }
     $aux_phids = array();
     foreach ($aux_fields as $key => $aux_field) {
         $aux_phids[$key] = $aux_field->getRequiredHandlePHIDsForRevisionView();
     }
     $object_phids = array_merge($object_phids, array_mergev($aux_phids));
     $object_phids = array_unique($object_phids);
     $handles = id(new PhabricatorObjectHandleData($object_phids))->loadHandles();
     foreach ($aux_fields as $key => $aux_field) {
         // Make sure each field only has access to handles it specifically
         // requested, not all handles. Otherwise you can get a field which works
         // only in the presence of other fields.
         $aux_field->setHandles(array_select_keys($handles, $aux_phids[$key]));
     }
     $reviewer_warning = null;
     $has_live_reviewer = false;
     foreach ($revision->getReviewers() as $reviewer) {
         if (!$handles[$reviewer]->isDisabled()) {
             $has_live_reviewer = true;
         }
     }
     if (!$has_live_reviewer) {
         $reviewer_warning = new AphrontErrorView();
         $reviewer_warning->setSeverity(AphrontErrorView::SEVERITY_WARNING);
         $reviewer_warning->setTitle('No Active Reviewers');
         if ($revision->getReviewers()) {
             $reviewer_warning->appendChild('<p>All specified reviewers are disabled. You may want to add ' . 'some new reviewers.</p>');
         } else {
             $reviewer_warning->appendChild('<p>This revision has no specified reviewers. You may want to ' . 'add some.</p>');
         }
     }
     $request_uri = $request->getRequestURI();
     $limit = 100;
     $large = $request->getStr('large');
     if (count($changesets) > $limit && !$large) {
         $count = number_format(count($changesets));
         $warning = new AphrontErrorView();
         $warning->setTitle('Very Large Diff');
         $warning->setSeverity(AphrontErrorView::SEVERITY_WARNING);
         $warning->setWidth(AphrontErrorView::WIDTH_WIDE);
         $warning->appendChild("<p>This diff is very large and affects {$count} files. Use " . "Table of Contents to open files in a standalone view. " . "<strong>" . phutil_render_tag('a', array('href' => $request_uri->alter('large', 'true')->setFragment('differential-review-toc')), 'Show All Files Inline') . "</strong>");
         $warning = $warning->render();
         $visible_changesets = array();
     } else {
         $warning = null;
         $visible_changesets = $changesets;
     }
     $revision_detail = new DifferentialRevisionDetailView();
     $revision_detail->setRevision($revision);
     $revision_detail->setAuxiliaryFields($aux_fields);
     $actions = $this->getRevisionActions($revision);
     $custom_renderer_class = PhabricatorEnv::getEnvConfig('differential.revision-custom-detail-renderer');
     if ($custom_renderer_class) {
         // TODO: build a better version of the action links and deprecate the
         // whole DifferentialRevisionDetailRenderer class.
         PhutilSymbolLoader::loadClass($custom_renderer_class);
         $custom_renderer = newv($custom_renderer_class, array());
         $actions = array_merge($actions, $custom_renderer->generateActionLinks($revision, $target));
     }
     $whitespace = $request->getStr('whitespace', DifferentialChangesetParser::WHITESPACE_IGNORE_ALL);
     $arc_project = $target->loadArcanistProject();
     if ($arc_project) {
         $symbol_indexes = $this->buildSymbolIndexes($target, $arc_project, $visible_changesets);
         $repository = $arc_project->loadRepository();
     } else {
         $symbol_indexes = array();
         $repository = null;
     }
     $revision_detail->setActions($actions);
     $revision_detail->setUser($user);
     $comment_view = new DifferentialRevisionCommentListView();
     $comment_view->setComments($comments);
     $comment_view->setHandles($handles);
     $comment_view->setInlineComments($inlines);
     $comment_view->setChangesets($all_changesets);
     $comment_view->setUser($user);
     $comment_view->setTargetDiff($target);
     $comment_view->setVersusDiffID($diff_vs);
     $changeset_view = new DifferentialChangesetListView();
     $changeset_view->setChangesets($visible_changesets);
     if (!$viewer_is_anonymous) {
         $changeset_view->setInlineCommentControllerURI('/differential/comment/inline/edit/' . $revision->getID() . '/');
     }
     $changeset_view->setStandaloneURI('/differential/changeset/');
     $changeset_view->setRawFileURIs('/differential/changeset/?view=old', '/differential/changeset/?view=new');
     $changeset_view->setUser($user);
     $changeset_view->setDiff($target);
     $changeset_view->setRenderingReferences($rendering_references);
     $changeset_view->setVsMap($vs_map);
     $changeset_view->setWhitespace($whitespace);
     if ($repository) {
         $changeset_view->setRepository($repository, $target);
     }
     $changeset_view->setSymbolIndexes($symbol_indexes);
     $diff_history = new DifferentialRevisionUpdateHistoryView();
     $diff_history->setDiffs($diffs);
     $diff_history->setSelectedVersusDiffID($diff_vs);
     $diff_history->setSelectedDiffID($target->getID());
     $diff_history->setSelectedWhitespace($whitespace);
     $diff_history->setUser($user);
     $local_view = new DifferentialLocalCommitsView();
     $local_view->setUser($user);
     $local_view->setLocalCommits(idx($props, 'local:commits'));
     if ($repository) {
         $other_revisions = $this->loadOtherRevisions($changesets, $target, $repository);
     } else {
         $other_revisions = array();
     }
     $other_view = null;
     if ($other_revisions) {
         $other_view = $this->renderOtherRevisions($other_revisions);
     }
     $toc_view = new DifferentialDiffTableOfContentsView();
     $toc_view->setChangesets($changesets);
     $toc_view->setVisibleChangesets($visible_changesets);
     $toc_view->setUnitTestData(idx($props, 'arc:unit', array()));
     if ($repository) {
         $toc_view->setRepository($repository);
     }
     $toc_view->setDiff($target);
     $toc_view->setUser($user);
     $toc_view->setStandaloneViewLink(empty($visible_changesets));
     $toc_view->setVsMap($vs_map);
     $toc_view->setRevisionID($revision->getID());
     $toc_view->setWhitespace($whitespace);
     if (!$viewer_is_anonymous) {
         $draft = id(new PhabricatorDraft())->loadOneWhere('authorPHID = %s AND draftKey = %s', $user->getPHID(), 'differential-comment-' . $revision->getID());
         if ($draft) {
             $draft = $draft->getDraft();
         } else {
             $draft = null;
         }
         $comment_form = new DifferentialAddCommentView();
         $comment_form->setRevision($revision);
         $comment_form->setActions($this->getRevisionCommentActions($revision));
         $comment_form->setActionURI('/differential/comment/save/');
         $comment_form->setUser($user);
         $comment_form->setDraft($draft);
     }
     $pane_id = celerity_generate_unique_node_id();
     Javelin::initBehavior('differential-keyboard-navigation', array('haunt' => $pane_id));
     $page_pane = id(new DifferentialPrimaryPaneView())->setLineWidthFromChangesets($changesets)->setID($pane_id)->appendChild($comment_view->render() . $diff_history->render() . $warning . $local_view->render() . $toc_view->render() . $other_view . $changeset_view->render());
     if ($comment_form) {
         $page_pane->appendChild($comment_form->render());
     }
     return $this->buildStandardPageResponse(array($reviewer_warning, $revision_detail, $page_pane), array('title' => 'D' . $revision->getID() . ' ' . $revision->getTitle()));
 }
Пример #21
0
/**
 * @group library
 */
function __phutil_autoload($class)
{
    PhutilSymbolLoader::loadClass($class);
}
Пример #22
0
phutil_require_module('phutil', 'error');
PhutilErrorHandler::setErrorListener(array('DarkConsoleErrorLogPluginAPI', 'handleErrors'));
foreach (PhabricatorEnv::getEnvConfig('load-libraries') as $library) {
    phutil_load_library($library);
}
if (PhabricatorEnv::getEnvConfig('phabricator.setup')) {
    PhabricatorSetup::runSetup();
    return;
}
$host = $_SERVER['HTTP_HOST'];
$path = $_REQUEST['__path__'];
switch ($host) {
    default:
        $config_key = 'aphront.default-application-configuration-class';
        $config_class = PhabricatorEnv::getEnvConfig($config_key);
        PhutilSymbolLoader::loadClass($config_class);
        $application = newv($config_class, array());
        break;
}
$application->setHost($host);
$application->setPath($path);
$application->willBuildRequest();
$request = $application->buildRequest();
$application->setRequest($request);
list($controller, $uri_data) = $application->buildController();
try {
    $response = $controller->willBeginExecution();
    if (!$response) {
        $controller->willProcessRequest($uri_data);
        $response = $controller->processRequest();
    }
 public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     $revision = id(new DifferentialRevision())->load($this->revisionID);
     if (!$revision) {
         return new Aphront404Response();
     }
     $revision->loadRelationships();
     $diffs = $revision->loadDiffs();
     if (!$diffs) {
         throw new Exception("This revision has no diffs. Something has gone quite wrong.");
     }
     $diff_vs = $request->getInt('vs');
     $target = end($diffs);
     $target_id = $request->getInt('id');
     if ($target_id) {
         if (isset($diffs[$target_id])) {
             $target = $diffs[$target_id];
         }
     }
     $diffs = mpull($diffs, null, 'getID');
     if (empty($diffs[$diff_vs])) {
         $diff_vs = null;
     }
     list($changesets, $vs_map, $rendering_references) = $this->loadChangesetsAndVsMap($diffs, $diff_vs, $target);
     $comments = $revision->loadComments();
     $comments = array_merge($this->getImplicitComments($revision), $comments);
     $all_changesets = $changesets;
     $inlines = $this->loadInlineComments($comments, $all_changesets);
     $object_phids = array_merge($revision->getReviewers(), $revision->getCCPHIDs(), $revision->loadCommitPHIDs(), array($revision->getAuthorPHID(), $user->getPHID()), mpull($comments, 'getAuthorPHID'));
     foreach ($comments as $comment) {
         $metadata = $comment->getMetadata();
         $added_reviewers = idx($metadata, DifferentialComment::METADATA_ADDED_REVIEWERS);
         if ($added_reviewers) {
             foreach ($added_reviewers as $phid) {
                 $object_phids[] = $phid;
             }
         }
         $added_ccs = idx($metadata, DifferentialComment::METADATA_ADDED_CCS);
         if ($added_ccs) {
             foreach ($added_ccs as $phid) {
                 $object_phids[] = $phid;
             }
         }
     }
     if ($target->getArcanistProjectPHID()) {
         $object_phids[] = $target->getArcanistProjectPHID();
     }
     foreach ($revision->getAttached() as $type => $phids) {
         foreach ($phids as $phid => $info) {
             $object_phids[] = $phid;
         }
     }
     $object_phids = array_unique($object_phids);
     $handles = id(new PhabricatorObjectHandleData($object_phids))->loadHandles();
     $request_uri = $request->getRequestURI();
     $limit = 100;
     $large = $request->getStr('large');
     if (count($changesets) > $limit && !$large) {
         $count = number_format(count($changesets));
         $warning = new AphrontErrorView();
         $warning->setTitle('Very Large Diff');
         $warning->setSeverity(AphrontErrorView::SEVERITY_WARNING);
         $warning->setWidth(AphrontErrorView::WIDTH_WIDE);
         $warning->appendChild("<p>This diff is very large and affects {$count} files. Use " . "Table of Contents to open files in a standalone view. " . "<strong>" . phutil_render_tag('a', array('href' => $request_uri->alter('large', 'true')), 'Show All Files Inline') . "</strong>");
         $warning = $warning->render();
         $visible_changesets = array();
     } else {
         $warning = null;
         $visible_changesets = $changesets;
     }
     $diff_properties = id(new DifferentialDiffProperty())->loadAllWhere('diffID = %d AND name IN (%Ls)', $target->getID(), array('arc:lint', 'arc:unit'));
     $diff_properties = mpull($diff_properties, 'getData', 'getName');
     $revision_detail = new DifferentialRevisionDetailView();
     $revision_detail->setRevision($revision);
     $custom_renderer_class = PhabricatorEnv::getEnvConfig('differential.revision-custom-detail-renderer');
     if ($custom_renderer_class) {
         PhutilSymbolLoader::loadClass($custom_renderer_class);
         $custom_renderer = newv($custom_renderer_class, array());
     } else {
         $custom_renderer = null;
     }
     $properties = $this->getRevisionProperties($revision, $target, $handles, $diff_properties);
     if ($custom_renderer) {
         $properties = array_merge($properties, $custom_renderer->generateProperties($revision, $target));
     }
     $revision_detail->setProperties($properties);
     $actions = $this->getRevisionActions($revision);
     if ($custom_renderer) {
         $actions = array_merge($actions, $custom_renderer->generateActionLinks($revision, $target));
     }
     $whitespace = $request->getStr('whitespace', DifferentialChangesetParser::WHITESPACE_IGNORE_ALL);
     $revision_detail->setActions($actions);
     $revision_detail->setUser($user);
     $comment_view = new DifferentialRevisionCommentListView();
     $comment_view->setComments($comments);
     $comment_view->setHandles($handles);
     $comment_view->setInlineComments($inlines);
     $comment_view->setChangesets($all_changesets);
     $comment_view->setUser($user);
     $comment_view->setTargetDiff($target);
     $changeset_view = new DifferentialChangesetListView();
     $changeset_view->setChangesets($visible_changesets);
     $changeset_view->setEditable(true);
     $changeset_view->setStandaloneViews(true);
     $changeset_view->setRevision($revision);
     $changeset_view->setRenderingReferences($rendering_references);
     $changeset_view->setWhitespace($whitespace);
     $diff_history = new DifferentialRevisionUpdateHistoryView();
     $diff_history->setDiffs($diffs);
     $diff_history->setSelectedVersusDiffID($diff_vs);
     $diff_history->setSelectedDiffID($target->getID());
     $diff_history->setSelectedWhitespace($whitespace);
     $toc_view = new DifferentialDiffTableOfContentsView();
     $toc_view->setChangesets($changesets);
     $toc_view->setStandaloneViewLink(empty($visible_changesets));
     $toc_view->setVsMap($vs_map);
     $toc_view->setRevisionID($revision->getID());
     $toc_view->setWhitespace($whitespace);
     $draft = id(new PhabricatorDraft())->loadOneWhere('authorPHID = %s AND draftKey = %s', $user->getPHID(), 'differential-comment-' . $revision->getID());
     if ($draft) {
         $draft = $draft->getDraft();
     } else {
         $draft = null;
     }
     $comment_form = new DifferentialAddCommentView();
     $comment_form->setRevision($revision);
     $comment_form->setActions($this->getRevisionCommentActions($revision));
     $comment_form->setActionURI('/differential/comment/save/');
     $comment_form->setUser($user);
     $comment_form->setDraft($draft);
     $this->updateViewTime($user->getPHID(), $revision->getPHID());
     $pane_id = celerity_generate_unique_node_id();
     Javelin::initBehavior('differential-keyboard-navigation', array('haunt' => $pane_id));
     return $this->buildStandardPageResponse(id(new DifferentialPrimaryPaneView())->setLineWidthFromChangesets($changesets)->setID($pane_id)->appendChild($revision_detail->render() . $comment_view->render() . $diff_history->render() . $warning . $toc_view->render() . $changeset_view->render() . $comment_form->render()), array('title' => 'D' . $revision->getID() . ' ' . $revision->getTitle()));
 }
 public function run()
 {
     $svnargs = $this->getArgument('svnargs');
     $repository = $svnargs[0];
     $transaction = $svnargs[1];
     list($commit_message) = execx('svnlook log --transaction %s %s', $transaction, $repository);
     if (strpos($commit_message, '@bypass-lint') !== false) {
         return 0;
     }
     // TODO: Do stuff with commit message.
     list($changed) = execx('svnlook changed --transaction %s %s', $transaction, $repository);
     $paths = array();
     $changed = explode("\n", trim($changed));
     foreach ($changed as $line) {
         $matches = null;
         preg_match('/^..\\s*(.*)$/', $line, $matches);
         $paths[$matches[1]] = strlen($matches[1]);
     }
     $resolved = array();
     $failed = array();
     $missing = array();
     $found = array();
     asort($paths);
     foreach ($paths as $path => $length) {
         foreach ($resolved as $rpath => $root) {
             if (!strncmp($path, $rpath, strlen($rpath))) {
                 $resolved[$path] = $root;
                 continue 2;
             }
         }
         $config = $path;
         if (basename($config) == '.arcconfig') {
             $resolved[$config] = $config;
             continue;
         }
         $config = rtrim($config, '/');
         $last_config = $config;
         do {
             if (!empty($missing[$config])) {
                 break;
             } else {
                 if (!empty($found[$config])) {
                     $resolved[$path] = $found[$config];
                     break;
                 }
             }
             list($err) = exec_manual('svnlook cat --transaction %s %s %s', $transaction, $repository, $config ? $config . '/.arcconfig' : '.arcconfig');
             if ($err) {
                 $missing[$path] = true;
             } else {
                 $resolved[$path] = $config ? $config . '/.arcconfig' : '.arcconfig';
                 $found[$config] = $resolved[$path];
                 break;
             }
             $config = dirname($config);
             if ($config == '.') {
                 $config = '';
             }
             if ($config == $last_config) {
                 break;
             }
             $last_config = $config;
         } while (true);
         if (empty($resolved[$path])) {
             $failed[] = $path;
         }
     }
     if ($failed && $resolved) {
         $failed_paths = '        ' . implode("\n        ", $failed);
         $resolved_paths = '        ' . implode("\n        ", array_keys($resolved));
         throw new ArcanistUsageException("This commit includes a mixture of files in Arcanist projects and " . "outside of Arcanist projects. A commit which affects an Arcanist " . "project must affect only that project.\n\n" . "Files in projects:\n\n" . $resolved_paths . "\n\n" . "Files not in projects:\n\n" . $failed_paths);
     }
     if (!$resolved) {
         // None of the affected paths are beneath a .arcconfig file.
         return 0;
     }
     $groups = array();
     foreach ($resolved as $path => $project) {
         $groups[$project][] = $path;
     }
     if (count($groups) > 1) {
         $message = array();
         foreach ($groups as $project => $group) {
             $message[] = "Files underneath '{$project}':\n\n";
             $message[] = "        " . implode("\n        ", $group) . "\n\n";
         }
         $message = implode('', $message);
         throw new ArcanistUsageException("This commit includes a mixture of files from different Arcanist " . "projects. A commit which affects an Arcanist project must affect " . "only that project.\n\n" . $message);
     }
     $config_file = key($groups);
     $project_root = dirname($config_file);
     $paths = reset($groups);
     list($config) = execx('svnlook cat --transaction %s %s %s', $transaction, $repository, $config_file);
     $working_copy = ArcanistWorkingCopyIdentity::newFromRootAndConfigFile($project_root, $config, $config_file . " (svnlook: {$transaction} {$repository})");
     $repository_api = new ArcanistSubversionHookAPI($project_root, $transaction, $repository);
     $lint_engine = $working_copy->getConfig('lint_engine');
     if (!$lint_engine) {
         return 0;
     }
     PhutilSymbolLoader::loadClass($lint_engine);
     $engine = newv($lint_engine, array());
     $engine->setWorkingCopy($working_copy);
     $engine->setMinimumSeverity(ArcanistLintSeverity::SEVERITY_ERROR);
     $engine->setPaths($paths);
     $engine->setCommitHookMode(true);
     $engine->setHookAPI($repository_api);
     try {
         $results = $engine->run();
     } catch (ArcanistNoEffectException $no_effect) {
         // Nothing to do, bail out.
         return 0;
     }
     $renderer = new ArcanistLintRenderer();
     $failures = array();
     foreach ($results as $result) {
         if (!$result->getMessages()) {
             continue;
         }
         $failures[] = $result;
     }
     if ($failures) {
         $at = "@";
         $msg = phutil_console_format("\n**LINT ERRORS**\n\n" . "This changeset has lint errors. You must fix all lint errors before " . "you can commit.\n\n" . "You can add '{$at}bypass-lint' to your commit message to disable " . "lint checks for this commit, or '{$at}nolint' to the file with " . "errors to disable lint for that file.\n\n");
         echo phutil_console_wrap($msg);
         foreach ($failures as $result) {
             echo $renderer->renderLintResult($result);
         }
         return 1;
     }
     return 0;
 }
Пример #25
0
 public function run()
 {
     $working_copy = $this->getWorkingCopy();
     $engine = $this->getArgument('engine');
     if (!$engine) {
         $engine = $working_copy->getConfig('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);
     PhutilSymbolLoader::loadClass($engine);
     if (!is_subclass_of($engine, 'ArcanistLintEngine')) {
         throw new ArcanistUsageException("Configured lint engine '{$engine}' is not a subclass of " . "'ArcanistLintEngine'.");
     }
     $engine = newv($engine, array());
     $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'));
         }
     }
     $results = $engine->run();
     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 ArcanistLintRenderer();
             $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);
             $old = $patcher->getUnmodifiedFileContent();
             $new = $patcher->getModifiedFileContent();
             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();
                 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 {
             $result_code = self::RESULT_OKAY;
         }
     }
     if (!$this->getParentWorkflow()) {
         if ($result_code == self::RESULT_OKAY) {
             echo $renderer->renderOkayResult();
         }
     }
     return $result_code;
 }
 public function loadHandles()
 {
     $types = array();
     foreach ($this->phids as $phid) {
         $type = $this->lookupType($phid);
         $types[$type][] = $phid;
     }
     $handles = array();
     $external_loaders = PhabricatorEnv::getEnvConfig('phid.external-loaders');
     foreach ($types as $type => $phids) {
         switch ($type) {
             case PhabricatorPHIDConstants::PHID_TYPE_MAGIC:
                 // Black magic!
                 foreach ($phids as $phid) {
                     $handle = new PhabricatorObjectHandle();
                     $handle->setPHID($phid);
                     $handle->setType($type);
                     switch ($phid) {
                         case ManiphestTaskOwner::OWNER_UP_FOR_GRABS:
                             $handle->setName('Up For Grabs');
                             $handle->setFullName('upforgrabs (Up For Grabs)');
                             break;
                         default:
                             $handle->setName('Foul Magicks');
                             break;
                     }
                     $handles[$phid] = $handle;
                 }
                 break;
             case PhabricatorPHIDConstants::PHID_TYPE_USER:
                 $class = 'PhabricatorUser';
                 PhutilSymbolLoader::loadClass($class);
                 $object = newv($class, array());
                 $users = $object->loadAllWhere('phid IN (%Ls)', $phids);
                 $users = mpull($users, null, 'getPHID');
                 foreach ($phids as $phid) {
                     $handle = new PhabricatorObjectHandle();
                     $handle->setPHID($phid);
                     $handle->setType($type);
                     if (empty($users[$phid])) {
                         $handle->setName('Unknown User');
                     } else {
                         $user = $users[$phid];
                         $handle->setName($user->getUsername());
                         $handle->setURI('/p/' . $user->getUsername() . '/');
                         $handle->setEmail($user->getEmail());
                         $handle->setFullName($user->getUsername() . ' (' . $user->getRealName() . ')');
                         $handle->setAlternateID($user->getID());
                         $img_phid = $user->getProfileImagePHID();
                         if ($img_phid) {
                             $handle->setImageURI(PhabricatorFileURI::getViewURIForPHID($img_phid));
                         }
                     }
                     $handles[$phid] = $handle;
                 }
                 break;
             case PhabricatorPHIDConstants::PHID_TYPE_MLST:
                 $class = 'PhabricatorMetaMTAMailingList';
                 PhutilSymbolLoader::loadClass($class);
                 $object = newv($class, array());
                 $lists = $object->loadAllWhere('phid IN (%Ls)', $phids);
                 $lists = mpull($lists, null, 'getPHID');
                 foreach ($phids as $phid) {
                     $handle = new PhabricatorObjectHandle();
                     $handle->setPHID($phid);
                     $handle->setType($type);
                     if (empty($lists[$phid])) {
                         $handle->setName('Unknown Mailing List');
                     } else {
                         $list = $lists[$phid];
                         $handle->setEmail($list->getEmail());
                         $handle->setName($list->getName());
                         $handle->setURI($list->getURI());
                         $handle->setFullName($list->getName());
                     }
                     $handles[$phid] = $handle;
                 }
                 break;
             case PhabricatorPHIDConstants::PHID_TYPE_DREV:
                 $class = 'DifferentialRevision';
                 PhutilSymbolLoader::loadClass($class);
                 $object = newv($class, array());
                 $revs = $object->loadAllWhere('phid in (%Ls)', $phids);
                 $revs = mpull($revs, null, 'getPHID');
                 foreach ($phids as $phid) {
                     $handle = new PhabricatorObjectHandle();
                     $handle->setPHID($phid);
                     $handle->setType($type);
                     if (empty($revs[$phid])) {
                         $handle->setName('Unknown Revision');
                     } else {
                         $rev = $revs[$phid];
                         $handle->setName($rev->getTitle());
                         $handle->setURI('/D' . $rev->getID());
                         $handle->setFullName('D' . $rev->getID() . ': ' . $rev->getTitle());
                     }
                     $handles[$phid] = $handle;
                 }
                 break;
             case PhabricatorPHIDConstants::PHID_TYPE_CMIT:
                 $class = 'PhabricatorRepositoryCommit';
                 PhutilSymbolLoader::loadClass($class);
                 $object = newv($class, array());
                 $commits = $object->loadAllWhere('phid in (%Ls)', $phids);
                 $commits = mpull($commits, null, 'getPHID');
                 $repository_ids = mpull($commits, 'getRepositoryID');
                 $repositories = id(new PhabricatorRepository())->loadAllWhere('id in (%Ld)', array_unique($repository_ids));
                 $callsigns = mpull($repositories, 'getCallsign');
                 foreach ($phids as $phid) {
                     $handle = new PhabricatorObjectHandle();
                     $handle->setPHID($phid);
                     $handle->setType($type);
                     if (empty($commits[$phid]) || !isset($callsigns[$repository_ids[$phid]])) {
                         $handle->setName('Unknown Commit');
                     } else {
                         $commit = $commits[$phid];
                         $callsign = $callsigns[$repository_ids[$phid]];
                         $repository = $repositories[$repository_ids[$phid]];
                         $commit_identifier = $commit->getCommitIdentifier();
                         // In case where the repository for the commit was deleted,
                         // we don't have have info about the repository anymore.
                         if ($repository) {
                             $vcs = $repository->getVersionControlSystem();
                             if ($vcs == PhabricatorRepositoryType::REPOSITORY_TYPE_GIT) {
                                 $short_identifier = substr($commit_identifier, 0, 16);
                             } else {
                                 $short_identifier = $commit_identifier;
                             }
                             $handle->setName('r' . $callsign . $short_identifier);
                         } else {
                             $handle->setName('Commit ' . 'r' . $callsign . $commit_identifier);
                         }
                         $handle->setURI('/r' . $callsign . $commit_identifier);
                         $handle->setFullName('r' . $callsign . $commit_identifier);
                         $handle->setTimestamp($commit->getEpoch());
                     }
                     $handles[$phid] = $handle;
                 }
                 break;
             case PhabricatorPHIDConstants::PHID_TYPE_TASK:
                 $class = 'ManiphestTask';
                 PhutilSymbolLoader::loadClass($class);
                 $object = newv($class, array());
                 $tasks = $object->loadAllWhere('phid in (%Ls)', $phids);
                 $tasks = mpull($tasks, null, 'getPHID');
                 foreach ($phids as $phid) {
                     $handle = new PhabricatorObjectHandle();
                     $handle->setPHID($phid);
                     $handle->setType($type);
                     if (empty($tasks[$phid])) {
                         $handle->setName('Unknown Revision');
                     } else {
                         $task = $tasks[$phid];
                         $handle->setName($task->getTitle());
                         $handle->setURI('/T' . $task->getID());
                         $handle->setFullName('T' . $task->getID() . ': ' . $task->getTitle());
                     }
                     $handles[$phid] = $handle;
                 }
                 break;
             case PhabricatorPHIDConstants::PHID_TYPE_FILE:
                 $class = 'PhabricatorFile';
                 PhutilSymbolLoader::loadClass($class);
                 $object = newv($class, array());
                 $files = $object->loadAllWhere('phid IN (%Ls)', $phids);
                 $files = mpull($files, null, 'getPHID');
                 foreach ($phids as $phid) {
                     $handle = new PhabricatorObjectHandle();
                     $handle->setPHID($phid);
                     $handle->setType($type);
                     if (empty($files[$phid])) {
                         $handle->setName('Unknown File');
                     } else {
                         $file = $files[$phid];
                         $handle->setName($file->getName());
                         $handle->setURI($file->getViewURI());
                     }
                     $handles[$phid] = $handle;
                 }
                 break;
             case PhabricatorPHIDConstants::PHID_TYPE_PROJ:
                 $class = 'PhabricatorProject';
                 PhutilSymbolLoader::loadClass($class);
                 $object = newv($class, array());
                 $projects = $object->loadAllWhere('phid IN (%Ls)', $phids);
                 $projects = mpull($projects, null, 'getPHID');
                 foreach ($phids as $phid) {
                     $handle = new PhabricatorObjectHandle();
                     $handle->setPHID($phid);
                     $handle->setType($type);
                     if (empty($projects[$phid])) {
                         $handle->setName('Unknown Project');
                     } else {
                         $project = $projects[$phid];
                         $handle->setName($project->getName());
                         $handle->setURI('/project/view/' . $project->getID() . '/');
                     }
                     $handles[$phid] = $handle;
                 }
                 break;
             case PhabricatorPHIDConstants::PHID_TYPE_REPO:
                 $class = 'PhabricatorRepository';
                 PhutilSymbolLoader::loadClass($class);
                 $object = newv($class, array());
                 $repositories = $object->loadAllWhere('phid in (%Ls)', $phids);
                 $repositories = mpull($repositories, null, 'getPHID');
                 foreach ($phids as $phid) {
                     $handle = new PhabricatorObjectHandle();
                     $handle->setPHID($phid);
                     $handle->setType($type);
                     if (empty($repositories[$phid])) {
                         $handle->setName('Unknown Repository');
                     } else {
                         $repository = $repositories[$phid];
                         $handle->setName($repository->getCallsign());
                         $handle->setURI('/diffusion/' . $repository->getCallsign() . '/');
                     }
                     $handles[$phid] = $handle;
                 }
                 break;
             case PhabricatorPHIDConstants::PHID_TYPE_OPKG:
                 $class = 'PhabricatorOwnersPackage';
                 PhutilSymbolLoader::loadClass($class);
                 $object = newv($class, array());
                 $packages = $object->loadAllWhere('phid in (%Ls)', $phids);
                 $packages = mpull($packages, null, 'getPHID');
                 foreach ($phids as $phid) {
                     $handle = new PhabricatorObjectHandle();
                     $handle->setPHID($phid);
                     $handle->setType($type);
                     if (empty($packages[$phid])) {
                         $handle->setName('Unknown Package');
                     } else {
                         $package = $packages[$phid];
                         $handle->setName($package->getName());
                         $handle->setURI('/owners/package/' . $package->getID() . '/');
                     }
                     $handles[$phid] = $handle;
                 }
                 break;
             case PhabricatorPHIDConstants::PHID_TYPE_APRJ:
                 $project_dao = newv('PhabricatorRepositoryArcanistProject', array());
                 $projects = $project_dao->loadAllWhere('phid IN (%Ls)', $phids);
                 $projects = mpull($projects, null, 'getPHID');
                 foreach ($phids as $phid) {
                     $handle = new PhabricatorObjectHandle();
                     $handle->setPHID($phid);
                     $handle->setType($type);
                     if (empty($projects[$phid])) {
                         $handle->setName('Unknown Arcanist Project');
                     } else {
                         $project = $projects[$phid];
                         $handle->setName($project->getName());
                     }
                     $handles[$phid] = $handle;
                 }
                 break;
             case PhabricatorPHIDConstants::PHID_TYPE_WIKI:
                 $document_dao = newv('PhrictionDocument', array());
                 $content_dao = newv('PhrictionContent', array());
                 $conn = $document_dao->establishConnection('r');
                 $documents = queryfx_all($conn, 'SELECT * FROM %T document JOIN %T content
           ON document.contentID = content.id
           WHERE document.phid IN (%Ls)', $document_dao->getTableName(), $content_dao->getTableName(), $phids);
                 $documents = ipull($documents, null, 'phid');
                 foreach ($phids as $phid) {
                     $handle = new PhabricatorObjectHandle();
                     $handle->setPHID($phid);
                     $handle->setType($type);
                     if (empty($documents[$phid])) {
                         $handle->setName('Unknown Document');
                     } else {
                         $info = $documents[$phid];
                         $handle->setName($info['title']);
                         $handle->setURI(PhrictionDocument::getSlugURI($info['slug']));
                     }
                     $handles[$phid] = $handle;
                 }
                 break;
             default:
                 $loader = null;
                 if (isset($external_loaders[$type])) {
                     $loader = $external_loaders[$type];
                 } else {
                     if (isset($external_loaders['*'])) {
                         $loader = $external_loaders['*'];
                     }
                 }
                 if ($loader) {
                     PhutilSymbolLoader::loadClass($loader);
                     $object = newv($loader, array());
                     $handles += $object->loadHandles($phids);
                     break;
                 }
                 foreach ($phids as $phid) {
                     $handle = new PhabricatorObjectHandle();
                     $handle->setType($type);
                     $handle->setPHID($phid);
                     $handle->setName('Unknown Object');
                     $handle->setFullName('An Unknown Object');
                     $handles[$phid] = $handle;
                 }
                 break;
         }
     }
     return $handles;
 }
Пример #27
0
 public function run()
 {
     $bootloader = PhutilBootloader::getInstance();
     $affected_modules = array();
     foreach ($this->getPaths() as $path) {
         $library_root = phutil_get_library_root_for_path($path);
         if (!$library_root) {
             continue;
         }
         $library_name = phutil_get_library_name_for_root($library_root);
         if (!$library_name) {
             throw new Exception("Attempting to run unit tests on a libphutil library which has not " . "been loaded, at:\n\n" . "    {$library_root}\n\n" . "This probably means one of two things:\n\n" . "    - You may need to add this library to .arcconfig.\n" . "    - You may be running tests on a copy of libphutil or arcanist\n" . "      using a different copy of libphutil or arcanist. This\n" . "      operation is not supported.");
         }
         $path = Filesystem::resolvePath($path);
         if (!is_dir($path)) {
             $path = dirname($path);
         }
         if ($path == $library_root) {
             continue;
         }
         $library_path = Filesystem::readablePath($path, $library_root);
         do {
             // Add the module and all parent modules as affected modules, which
             // means we'll look for __tests__ to run here and in any containing
             // module.
             $affected_modules[$library_name . ':' . $library_path] = array('name' => $library_name, 'root' => $library_root, 'path' => $library_path);
             $library_path = dirname($library_path);
         } while ($library_path != '.');
     }
     $tests = array();
     foreach ($affected_modules as $library_info) {
         $library_name = $library_info['name'];
         $library_root = $library_info['root'];
         $module = $library_info['path'];
         if (basename($module) == '__tests__') {
             // Okay, this is a __tests__ module.
         } else {
             $exists = $bootloader->moduleExists($library_name, $module . '/__tests__');
             if ($exists) {
                 // This is a module which has a __tests__ module in it.
                 $module .= '/__tests__';
             } else {
                 // Look for a parent named __tests__.
                 $rpos = strrpos($module, '/__tests__');
                 if ($rpos === false) {
                     // No tests to run since there is no child or parent module named
                     // __tests__.
                     continue;
                 }
                 // Select the parent named __tests__.
                 $module = substr($module, 0, $rpos + strlen('/__tests__'));
             }
         }
         $module_key = $library_name . ':' . $module;
         $tests[$module_key] = array('library' => $library_name, 'root' => $library_root, 'module' => $module);
     }
     if (!$tests) {
         throw new ArcanistNoEffectException("No tests to run.");
     }
     $run_tests = array();
     foreach ($tests as $test) {
         $symbols = id(new PhutilSymbolLoader())->setType('class')->setLibrary($test['library'])->setModule($test['module'])->setAncestorClass('ArcanistPhutilTestCase')->selectAndLoadSymbols();
         foreach ($symbols as $symbol) {
             $run_tests[$symbol['name']] = true;
         }
     }
     $run_tests = array_keys($run_tests);
     if (!$run_tests) {
         throw new ArcanistNoEffectException("No tests to run. You may need to rebuild the phutil library map.");
     }
     $enable_coverage = $this->getEnableCoverage();
     if ($enable_coverage !== false) {
         if (!function_exists('xdebug_start_code_coverage')) {
             if ($enable_coverage === true) {
                 throw new ArcanistUsageException("You specified --coverage but xdebug is not available, so " . "coverage can not be enabled for PhutilUnitTestEngine.");
             }
         } else {
             $enable_coverage = true;
         }
     }
     $results = array();
     foreach ($run_tests as $test_class) {
         PhutilSymbolLoader::loadClass($test_class);
         $test_case = newv($test_class, array());
         $test_case->setEnableCoverage($enable_coverage);
         $test_case->setProjectRoot($this->getWorkingCopy()->getProjectRoot());
         $test_case->setPaths($this->getPaths());
         $results[] = $test_case->run();
     }
     if ($results) {
         $results = call_user_func_array('array_merge', $results);
     }
     return $results;
 }
 public function run()
 {
     $lease_ownership_name = $this->getLeaseOwnershipName();
     $task_table = new PhabricatorWorkerTask();
     $taskdata_table = new PhabricatorWorkerTaskData();
     $sleep = 0;
     do {
         $conn_w = $task_table->establishConnection('w');
         queryfx($conn_w, 'UPDATE %T SET leaseOwner = %s, leaseExpires = UNIX_TIMESTAMP() + 15
       WHERE leaseOwner IS NULL LIMIT 1', $task_table->getTableName(), $lease_ownership_name);
         $rows = $conn_w->getAffectedRows();
         if (!$rows) {
             $rows = queryfx($conn_w, 'UPDATE %T SET leaseOwner = %s, leaseExpires = UNIX_TIMESTAMP() + 15
         WHERE leaseExpires < UNIX_TIMESTAMP() LIMIT 1', $task_table->getTableName(), $lease_ownership_name);
             $rows = $conn_w->getAffectedRows();
         }
         if ($rows) {
             $data = queryfx_all($conn_w, 'SELECT task.*, taskdata.data _taskData, UNIX_TIMESTAMP() _serverTime
         FROM %T task LEFT JOIN %T taskdata
           ON taskdata.id = task.dataID
         WHERE leaseOwner = %s AND leaseExpires > UNIX_TIMESTAMP()
         LIMIT 1', $task_table->getTableName(), $taskdata_table->getTableName(), $lease_ownership_name);
             $tasks = $task_table->loadAllFromArray($data);
             $tasks = mpull($tasks, null, 'getID');
             $task_data = array();
             foreach ($data as $row) {
                 $tasks[$row['id']]->setServerTime($row['_serverTime']);
                 if ($row['_taskData']) {
                     $task_data[$row['id']] = json_decode($row['_taskData'], true);
                 } else {
                     $task_data[$row['id']] = null;
                 }
             }
             foreach ($tasks as $task) {
                 // TODO: We should detect if we acquired a task with an expired lease
                 // and log about it / bump up failure count.
                 // TODO: We should detect if we acquired a task with an excessive
                 // failure count and fail it permanently.
                 $data = idx($task_data, $task->getID());
                 $class = $task->getTaskClass();
                 try {
                     PhutilSymbolLoader::loadClass($class);
                     if (!is_subclass_of($class, 'PhabricatorWorker')) {
                         throw new Exception("Task class '{$class}' does not extend PhabricatorWorker.");
                     }
                     $worker = newv($class, array($data));
                     $lease = $worker->getRequiredLeaseTime();
                     if ($lease !== null) {
                         $task->setLeaseDuration($lease);
                     }
                     $worker->executeTask();
                     $task->delete();
                     if ($data !== null) {
                         queryfx($conn_w, 'DELETE FROM %T WHERE id = %d', $taskdata_table->getTableName(), $task->getDataID());
                     }
                 } catch (Exception $ex) {
                     $task->setFailureCount($task->getFailureCount() + 1);
                     $task->save();
                     throw $ex;
                 }
             }
             $sleep = 0;
         } else {
             $sleep = min($sleep + 1, 30);
         }
         $this->sleep($sleep);
     } while (true);
 }
 private static function newMarkupEngine(array $options)
 {
     $options += self::getMarkupEngineDefaultConfiguration();
     $engine = new PhutilRemarkupEngine();
     $engine->setConfig('preserve-linebreaks', true);
     $engine->setConfig('pygments.enabled', $options['pygments']);
     $rules = array();
     $rules[] = new PhutilRemarkupRuleEscapeRemarkup();
     if ($options['fileproxy']) {
         $rules[] = new PhabricatorRemarkupRuleProxyImage();
     }
     if ($options['youtube']) {
         $rules[] = new PhabricatorRemarkupRuleYoutube();
     }
     $rules[] = new PhutilRemarkupRuleHyperlink();
     $rules[] = new PhabricatorRemarkupRuleDifferential();
     $rules[] = new PhabricatorRemarkupRuleDiffusion();
     $rules[] = new PhabricatorRemarkupRuleManiphest();
     $rules[] = new PhabricatorRemarkupRulePaste();
     if ($options['macros']) {
         $rules[] = new PhabricatorRemarkupRuleImageMacro();
     }
     $rules[] = new PhabricatorRemarkupRuleMention();
     $rules[] = new PhabricatorRemarkupRulePhriction();
     $custom_rule_classes = $options['custom-inline'];
     if ($custom_rule_classes) {
         foreach ($custom_rule_classes as $custom_rule_class) {
             PhutilSymbolLoader::loadClass($custom_rule_class);
             $rules[] = newv($custom_rule_class, array());
         }
     }
     $rules[] = new PhutilRemarkupRuleEscapeHTML();
     $rules[] = new PhutilRemarkupRuleMonospace();
     $rules[] = new PhutilRemarkupRuleBold();
     $rules[] = new PhutilRemarkupRuleItalic();
     $blocks = array();
     $blocks[] = new PhutilRemarkupEngineRemarkupQuotesBlockRule();
     $blocks[] = new PhutilRemarkupEngineRemarkupHeaderBlockRule();
     $blocks[] = new PhutilRemarkupEngineRemarkupListBlockRule();
     $blocks[] = new PhutilRemarkupEngineRemarkupCodeBlockRule();
     $blocks[] = new PhutilRemarkupEngineRemarkupDefaultBlockRule();
     $custom_block_rule_classes = $options['custom-block'];
     if ($custom_block_rule_classes) {
         foreach ($custom_block_rule_classes as $custom_block_rule_class) {
             PhutilSymbolLoader::loadClass($custom_block_rule_class);
             $blocks[] = newv($custom_block_rule_class, array());
         }
     }
     foreach ($blocks as $block) {
         if (!$block instanceof PhutilRemarkupEngineRemarkupCodeBlockRule) {
             $block->setMarkupRules($rules);
         }
     }
     $engine->setBlockRules($blocks);
     return $engine;
 }
Пример #30
0
 public function run()
 {
     $working_copy = $this->getWorkingCopy();
     $engine_class = $this->getArgument('engine', $working_copy->getConfig('unit_engine'));
     if (!$engine_class) {
         throw new ArcanistNoEngineException("No unit test engine is configured for this project. Edit .arcconfig " . "to specify a unit test engine.");
     }
     $paths = $this->getArgument('paths');
     $rev = $this->getArgument('rev');
     $paths = $this->selectPathsForWorkflow($paths, $rev);
     PhutilSymbolLoader::loadClass($engine_class);
     if (!is_subclass_of($engine_class, 'ArcanistBaseUnitTestEngine')) {
         throw new ArcanistUsageException("Configured unit test engine '{$engine_class}' is not a subclass of " . "'ArcanistBaseUnitTestEngine'.");
     }
     $this->engine = newv($engine_class, array());
     $this->engine->setWorkingCopy($working_copy);
     $this->engine->setPaths($paths);
     $this->engine->setArguments($this->getPassthruArgumentsAsMap('unit'));
     $enable_coverage = null;
     // Means "default".
     if ($this->getArgument('coverage') || $this->getArgument('detailed-coverage')) {
         $enable_coverage = true;
     } else {
         if ($this->getArgument('no-coverage')) {
             $enable_coverage = false;
         }
     }
     $this->engine->setEnableCoverage($enable_coverage);
     // Enable possible async tests only for 'arc diff' not 'arc unit'
     if ($this->getParentWorkflow()) {
         $this->engine->setEnableAsyncTests(true);
     } else {
         $this->engine->setEnableAsyncTests(false);
     }
     $results = $this->engine->run();
     $this->testResults = $results;
     $status_codes = array(ArcanistUnitTestResult::RESULT_PASS => phutil_console_format('<bg:green>** PASS **</bg>'), ArcanistUnitTestResult::RESULT_FAIL => phutil_console_format('<bg:red>** FAIL **</bg>'), ArcanistUnitTestResult::RESULT_SKIP => phutil_console_format('<bg:yellow>** SKIP **</bg>'), ArcanistUnitTestResult::RESULT_BROKEN => phutil_console_format('<bg:red>** BROKEN **</bg>'), ArcanistUnitTestResult::RESULT_UNSOUND => phutil_console_format('<bg:yellow>** UNSOUND **</bg>'), ArcanistUnitTestResult::RESULT_POSTPONED => phutil_console_format('<bg:yellow>** POSTPONED **</bg>'));
     $unresolved = array();
     $coverage = array();
     $postponed_count = 0;
     foreach ($results as $result) {
         $result_code = $result->getResult();
         if ($result_code == ArcanistUnitTestResult::RESULT_POSTPONED) {
             $postponed_count++;
             $unresolved[] = $result;
         } else {
             if ($this->engine->shouldEchoTestResults()) {
                 echo '  ' . $status_codes[$result_code];
                 if ($result_code == ArcanistUnitTestResult::RESULT_PASS) {
                     echo ' ' . self::formatTestDuration($result->getDuration());
                 }
                 echo ' ' . $result->getName() . "\n";
             }
             if ($result_code != ArcanistUnitTestResult::RESULT_PASS) {
                 if ($this->engine->shouldEchoTestResults()) {
                     echo $result->getUserData() . "\n";
                 }
                 $unresolved[] = $result;
             }
         }
         if ($result->getCoverage()) {
             foreach ($result->getCoverage() as $file => $report) {
                 $coverage[$file][] = $report;
             }
         }
     }
     if ($postponed_count) {
         echo sprintf("%s %d %s\n", $status_codes[ArcanistUnitTestResult::RESULT_POSTPONED], $postponed_count, $postponed_count > 1 ? 'tests' : 'test');
     }
     if ($coverage) {
         $file_coverage = array_fill_keys($paths, 0);
         $file_reports = array();
         foreach ($coverage as $file => $reports) {
             $report = ArcanistUnitTestResult::mergeCoverage($reports);
             $cov = substr_count($report, 'C');
             $uncov = substr_count($report, 'U');
             if ($cov + $uncov) {
                 $coverage = $cov / ($cov + $uncov);
             } else {
                 $coverage = 0;
             }
             $file_coverage[$file] = $coverage;
             $file_reports[$file] = $report;
         }
         echo "\n";
         echo phutil_console_format('__COVERAGE REPORT__');
         echo "\n";
         asort($file_coverage);
         foreach ($file_coverage as $file => $coverage) {
             echo phutil_console_format("    **%s%%**     %s\n", sprintf('% 3d', (int) (100 * $coverage)), $file);
             $full_path = $working_copy->getProjectRoot() . '/' . $file;
             if ($this->getArgument('detailed-coverage') && Filesystem::pathExists($full_path) && is_file($full_path)) {
                 echo $this->renderDetailedCoverageReport(Filesystem::readFile($full_path), $file_reports[$file]);
             }
         }
     }
     $this->unresolvedTests = $unresolved;
     $overall_result = self::RESULT_OKAY;
     foreach ($results as $result) {
         $result_code = $result->getResult();
         if ($result_code == ArcanistUnitTestResult::RESULT_FAIL || $result_code == ArcanistUnitTestResult::RESULT_BROKEN) {
             $overall_result = self::RESULT_FAIL;
             break;
         } else {
             if ($result_code == ArcanistUnitTestResult::RESULT_UNSOUND) {
                 $overall_result = self::RESULT_UNSOUND;
             } else {
                 if ($result_code == ArcanistUnitTestResult::RESULT_POSTPONED && $overall_result != self::RESULT_UNSOUND) {
                     $overall_result = self::RESULT_POSTPONED;
                 }
             }
         }
     }
     return $overall_result;
 }