private function buildNavItems() { $classes = $this->getAllMethodImplementationClasses(); $method_names = array(); foreach ($classes as $method_class) { $method_name = ConduitAPIMethod::getAPIMethodNameFromClassName($method_class); $parts = explode('.', $method_name); $method_names[] = array('full_name' => $method_name, 'group_name' => reset($parts)); } $method_names = igroup($method_names, 'group_name'); ksort($method_names); $items = array(); foreach ($method_names as $group => $methods) { $items[] = phutil_render_tag('a', array(), phutil_escape_html($group)); foreach ($methods as $method) { $method_name = $method['full_name']; $selected = $method_name == $this->method; $items[] = phutil_render_tag('a', array('class' => $selected ? 'aphront-side-nav-selected' : null, 'href' => '/conduit/method/' . $method_name), '<span style="padding-left: 1em;">' . phutil_escape_html($method_name) . '</span>'); } $items[] = '<hr />'; } // Pop off the last '<hr />'. array_pop($items); return $items; }
public function renderValueForRevisionView() { $diff = $this->getDiff(); $path_changesets = mpull($diff->loadChangesets(), 'getId', 'getFilename'); $lstar = DifferentialRevisionUpdateHistoryView::renderDiffLintStar($diff); $lmsg = DifferentialRevisionUpdateHistoryView::getDiffLintMessage($diff); $ldata = $this->getDiffProperty('arc:lint'); $ltail = null; if ($ldata) { $ldata = igroup($ldata, 'path'); $lint_messages = array(); foreach ($ldata as $path => $messages) { $message_markup = array(); foreach ($messages as $message) { $path = idx($message, 'path'); $line = idx($message, 'line'); $code = idx($message, 'code'); $severity = idx($message, 'severity'); $name = idx($message, 'name'); $description = idx($message, 'description'); $line_link = phutil_escape_html($line); if (isset($path_changesets[$path])) { // TODO: Create standalone links for large diffs. Logic is in // DifferentialDiffTableOfContentsView::renderChangesetLink(). $line_link = phutil_render_tag('a', array('href' => '#C' . $path_changesets[$path] . 'NL' . $line), $line_link); } $message_markup[] = hsprintf('<li>' . '<span class="lint-severity-%s">%s</span> (%s) %s ' . 'at line ' . $line_link . '<p>%s</p>' . '</li>', $severity, ucwords($severity), $code, $name, $description); } $lint_messages[] = '<li class="lint-file-block">' . 'Lint for <strong>' . phutil_escape_html($path) . '</strong>' . '<ul>' . implode("\n", $message_markup) . '</ul>' . '</li>'; } $lexcuse = $this->getLintExcuse(); $ltail = '<div class="differential-lint-block">' . $lexcuse . '<ul>' . implode("\n", $lint_messages) . '</ul>' . '</div>'; } return $lstar . ' ' . $lmsg . $ltail; }
public function renderValueForRevisionView() { $diff = $this->getDiff(); $lstar = DifferentialRevisionUpdateHistoryView::renderDiffLintStar($diff); $lmsg = DifferentialRevisionUpdateHistoryView::getDiffLintMessage($diff); $ldata = $this->getDiffProperty('arc:lint'); $ltail = null; if ($ldata) { $ldata = igroup($ldata, 'path'); $lint_messages = array(); foreach ($ldata as $path => $messages) { $message_markup = array(); foreach ($messages as $message) { $path = idx($message, 'path'); $line = idx($message, 'line'); $code = idx($message, 'code'); $severity = idx($message, 'severity'); $name = idx($message, 'name'); $description = idx($message, 'description'); $message_markup[] = '<li>' . '<span class="lint-severity-' . phutil_escape_html($severity) . '">' . phutil_escape_html(ucwords($severity)) . '</span>' . ' ' . '(' . phutil_escape_html($code) . ') ' . phutil_escape_html($name) . ' at line ' . phutil_escape_html($line) . '<p>' . phutil_escape_html($description) . '</p>' . '</li>'; } $lint_messages[] = '<li class="lint-file-block">' . 'Lint for <strong>' . phutil_escape_html($path) . '</strong>' . '<ul>' . implode("\n", $message_markup) . '</ul>' . '</li>'; } $ltail = '<div class="differential-lint-block">' . '<ul>' . implode("\n", $lint_messages) . '</ul>' . '</div>'; } return $lstar . ' ' . $lmsg . $ltail; }
public function executeListCommand() { $symbols = $this->loadAvailableDaemonClasses(); $symbols = igroup($symbols, 'library'); echo "\n"; foreach ($symbols as $library => $symbol_list) { echo phutil_console_format("Daemons in library __%s__:\n", $library); foreach ($symbol_list as $symbol) { echo " " . $symbol['name'] . "\n"; } echo "\n"; } return 0; }
public function execute(PhutilArgumentParser $args) { $console = PhutilConsole::getConsole(); $symbols = $this->loadAvailableDaemonClasses(); $symbols = igroup($symbols, 'library'); foreach ($symbols as $library => $symbol_list) { $console->writeOut(pht('Daemons in library __%s__:', $library) . "\n"); foreach ($symbol_list as $symbol) { $console->writeOut(" %s\n", $symbol['name']); } $console->writeOut("\n"); } return 0; }
public function handleRequest(AphrontRequest $request) { $viewer = $request->getUser(); $board_id = $request->getURIData('projectID'); $board = id(new PhabricatorProjectQuery())->setViewer($viewer)->withIDs(array($board_id))->needImages(true)->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->executeOne(); if (!$board) { return new Aphront404Response(); } if (!$board->getHasWorkboard()) { return new Aphront404Response(); } $this->setProject($board); $id = $board->getID(); $manage_uri = $this->getApplicationURI("board/{$id}/manage/"); if ($request->isFormPost()) { $background_key = $request->getStr('backgroundKey'); $xactions = array(); $xactions[] = id(new PhabricatorProjectTransaction())->setTransactionType(PhabricatorProjectTransaction::TYPE_BACKGROUND)->setNewValue($background_key); id(new PhabricatorProjectTransactionEditor())->setActor($viewer)->setContentSourceFromRequest($request)->setContinueOnNoEffect(true)->setContinueOnMissingFields(true)->applyTransactions($board, $xactions); return id(new AphrontRedirectResponse())->setURI($manage_uri); } $nav = $this->getProfileMenu(); $crumbs = id($this->buildApplicationCrumbs())->addTextCrumb(pht('Workboard'), "/project/board/{$board_id}/")->addTextCrumb(pht('Manage'), $manage_uri)->addTextCrumb(pht('Background Color')); $form = id(new AphrontFormView())->setUser($viewer); $group_info = array('basic' => array('label' => pht('Basics')), 'solid' => array('label' => pht('Solid Colors')), 'gradient' => array('label' => pht('Gradients'))); $groups = array(); $options = PhabricatorProjectWorkboardBackgroundColor::getOptions(); $option_groups = igroup($options, 'group'); require_celerity_resource('people-profile-css'); require_celerity_resource('phui-workboard-color-css'); Javelin::initBehavior('phabricator-tooltips', array()); foreach ($group_info as $group_key => $spec) { $buttons = array(); $available_options = idx($option_groups, $group_key, array()); foreach ($available_options as $option) { $buttons[] = $this->renderOptionButton($option); } $form->appendControl(id(new AphrontFormMarkupControl())->setLabel($spec['label'])->setValue($buttons)); } // NOTE: Each button is its own form, so we can't wrap them in a normal // form. $layout_view = $form->buildLayoutView(); $form_box = id(new PHUIObjectBoxView())->setHeaderText(pht('Edit Background Color'))->appendChild($layout_view); return $this->newPage()->setTitle(array(pht('Edit Background Color'), $board->getDisplayName()))->setCrumbs($crumbs)->setNavigation($nav)->appendChild($form_box); }
public static function loadAllByContentTypeWithFullData($content_type) { $rules = id(new HeraldRule())->loadAllWhere('contentType = %s', $content_type); if (!$rules) { return array(); } $rule_ids = mpull($rules, 'getID'); $conditions = id(new HeraldCondition())->loadAllWhere('ruleID in (%Ld)', $rule_ids); $actions = id(new HeraldAction())->loadAllWhere('ruleID in (%Ld)', $rule_ids); $applied = queryfx_all(id(new HeraldRule())->establishConnection('r'), 'SELECT * FROM %T WHERE ruleID in (%Ld)', self::TABLE_RULE_APPLIED, $rule_ids); $conditions = mgroup($conditions, 'getRuleID'); $actions = mgroup($actions, 'getRuleID'); $applied = igroup($applied, 'ruleID'); foreach ($rules as $rule) { $rule->attachAllRuleApplied(idx($applied, $rule->getID(), array())); $rule->attachConditions(idx($conditions, $rule->getID(), array())); $rule->attachActions(idx($actions, $rule->getID(), array())); } return $rules; }
public function processRequest() { $request = $this->getRequest(); $viewer = $request->getUser(); require_celerity_resource('diviner-shared-css'); $book = id(new DivinerBookQuery())->setViewer($viewer)->withNames(array($this->bookName))->executeOne(); if (!$book) { return new Aphront404Response(); } // TODO: This query won't load ghosts, because they'll fail `needAtoms()`. // Instead, we might want to load ghosts and render a message like // "this thing existed in an older version, but no longer does", especially // if we add content like comments. $symbol = id(new DivinerAtomQuery())->setViewer($viewer)->withBookPHIDs(array($book->getPHID()))->withTypes(array($this->atomType))->withNames(array($this->atomName))->withContexts(array($this->atomContext))->withIndexes(array($this->atomIndex))->needAtoms(true)->needExtends(true)->needChildren(true)->executeOne(); if (!$symbol) { return new Aphront404Response(); } $atom = $symbol->getAtom(); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb($book->getShortTitle(), '/book/' . $book->getName() . '/'); $atom_short_title = $atom->getDocblockMetaValue('short', $symbol->getTitle()); $crumbs->addTextCrumb($atom_short_title); $header = id(new PHUIHeaderView())->setHeader($this->renderFullSignature($symbol))->addTag(id(new PHUITagView())->setType(PHUITagView::TYPE_STATE)->setBackgroundColor(PHUITagView::COLOR_BLUE)->setName(DivinerAtom::getAtomTypeNameString($atom->getType()))); $properties = id(new PHUIPropertyListView()); $group = $atom->getProperty('group'); if ($group) { $group_name = $book->getGroupName($group); } else { $group_name = null; } $this->buildDefined($properties, $symbol); $this->buildExtendsAndImplements($properties, $symbol); $warnings = $atom->getWarnings(); if ($warnings) { $warnings = id(new AphrontErrorView())->setErrors($warnings)->setTitle(pht('Documentation Warnings'))->setSeverity(AphrontErrorView::SEVERITY_WARNING); } $methods = $this->composeMethods($symbol); $field = 'default'; $engine = id(new PhabricatorMarkupEngine())->setViewer($viewer)->addObject($symbol, $field); foreach ($methods as $method) { foreach ($method['atoms'] as $matom) { $engine->addObject($matom, $field); } } $engine->process(); $content = $this->renderDocumentationText($symbol, $engine); $toc = $engine->getEngineMetadata($symbol, $field, PhutilRemarkupHeaderBlockRule::KEY_HEADER_TOC, array()); $document = id(new PHUIDocumentView())->setBook($book->getTitle(), $group_name)->setHeader($header)->addClass('diviner-view')->setFontKit(PHUIDocumentView::FONT_SOURCE_SANS)->appendChild($properties)->appendChild($warnings)->appendChild($content); $document->appendChild($this->buildParametersAndReturn(array($symbol))); if ($methods) { $tasks = $this->composeTasks($symbol); if ($tasks) { $methods_by_task = igroup($methods, 'task'); // Add phantom tasks for methods which have a "@task" name that isn't // documented anywhere, or methods that have no "@task" name. foreach ($methods_by_task as $task => $ignored) { if (empty($tasks[$task])) { $tasks[$task] = array('name' => $task, 'title' => $task ? $task : pht('Other Methods'), 'defined' => $symbol); } } $section = id(new DivinerSectionView())->setHeader(pht('Tasks')); foreach ($tasks as $spec) { $section->addContent(id(new PHUIHeaderView())->setNoBackground(true)->setHeader($spec['title'])); $task_methods = idx($methods_by_task, $spec['name'], array()); $inner_box = id(new PHUIBoxView())->addPadding(PHUI::PADDING_LARGE_LEFT)->addPadding(PHUI::PADDING_LARGE_RIGHT)->addPadding(PHUI::PADDING_LARGE_BOTTOM); $box_content = array(); if ($task_methods) { $list_items = array(); foreach ($task_methods as $task_method) { $atom = last($task_method['atoms']); $item = $this->renderFullSignature($atom, true); if (strlen($atom->getSummary())) { $item = array($item, " — ", $atom->getSummary()); } $list_items[] = phutil_tag('li', array(), $item); } $box_content[] = phutil_tag('ul', array('class' => 'diviner-list'), $list_items); } else { $no_methods = pht('No methods for this task.'); $box_content = phutil_tag('em', array(), $no_methods); } $inner_box->appendChild($box_content); $section->addContent($inner_box); } $document->appendChild($section); } $section = id(new DivinerSectionView())->setHeader(pht('Methods')); foreach ($methods as $spec) { $matom = last($spec['atoms']); $method_header = id(new PHUIHeaderView())->setNoBackground(true); $inherited = $spec['inherited']; if ($inherited) { $method_header->addTag(id(new PHUITagView())->setType(PHUITagView::TYPE_STATE)->setBackgroundColor(PHUITagView::COLOR_GREY)->setName(pht('Inherited'))); } $method_header->setHeader($this->renderFullSignature($matom)); $section->addContent(array($method_header, $this->renderMethodDocumentationText($symbol, $spec, $engine), $this->buildParametersAndReturn($spec['atoms']))); } $document->appendChild($section); } if ($toc) { $side = new PHUIListView(); $side->addMenuItem(id(new PHUIListItemView())->setName(pht('Contents'))->setType(PHUIListItemView::TYPE_LABEL)); foreach ($toc as $key => $entry) { $side->addMenuItem(id(new PHUIListItemView())->setName($entry[1])->setHref('#' . $key)); } $document->setSideNav($side, PHUIDocumentView::NAV_TOP); } return $this->buildApplicationPage(array($crumbs, $document), array('title' => $symbol->getTitle())); }
private function loadHashes(AphrontDatabaseConnection $conn_r, array $revisions) { assert_instances_of($revisions, 'DifferentialRevision'); $data = queryfx_all($conn_r, 'SELECT * FROM %T WHERE revisionID IN (%Ld)', 'differential_revisionhash', mpull($revisions, 'getID')); $data = igroup($data, 'revisionID'); foreach ($revisions as $revision) { $hashes = idx($data, $revision->getID(), array()); $list = array(); foreach ($hashes as $hash) { $list[] = array($hash['type'], $hash['hash']); } $revision->attachHashes($list); } }
private function executeExtendedPolicyChecks(array $extended_objects) { $viewer = $this->viewer; $filter_capabilities = $this->capabilities; // Iterate over the objects we need to filter and pull all the nonempty // policies into a flat, structured list. $all_structs = array(); foreach ($extended_objects as $key => $extended_object) { foreach ($filter_capabilities as $extended_capability) { $extended_policies = $extended_object->getExtendedPolicy($extended_capability, $viewer); if (!$extended_policies) { continue; } foreach ($extended_policies as $extended_policy) { list($object, $capabilities) = $extended_policy; // Build a description of the capabilities we need to check. This // will be something like `"view"`, or `"edit view"`, or possibly // a longer string with custom capabilities. Later, group the objects // up into groups which need the same capabilities tested. $capabilities = (array) $capabilities; $capabilities = array_fuse($capabilities); ksort($capabilities); $group = implode(' ', $capabilities); $struct = array('key' => $key, 'for' => $extended_capability, 'object' => $object, 'capabilities' => $capabilities, 'group' => $group); $all_structs[] = $struct; } } } // Extract any bare PHIDs from the structs; we need to load these objects. // These are objects which are required in order to perform an extended // policy check but which the original viewer did not have permission to // see (they presumably had other permissions which let them load the // object in the first place). $all_phids = array(); foreach ($all_structs as $idx => $struct) { $object = $struct['object']; if (is_string($object)) { $all_phids[$object] = $object; } } // If we have some bare PHIDs, we need to load the corresponding objects. if ($all_phids) { // We can pull these with the omnipotent user because we're immediately // filtering them. $ref_objects = id(new PhabricatorObjectQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withPHIDs($all_phids)->execute(); $ref_objects = mpull($ref_objects, null, 'getPHID'); } else { $ref_objects = array(); } // Group the list of checks by the capabilities we need to check. $groups = igroup($all_structs, 'group'); foreach ($groups as $structs) { $head = head($structs); // All of the items in each group are checking for the same capabilities. $capabilities = $head['capabilities']; $key_map = array(); $objects_in = array(); foreach ($structs as $struct) { $extended_key = $struct['key']; if (empty($extended_objects[$key])) { // If this object has already been rejected by an earlier filtering // pass, we don't need to do any tests on it. continue; } $object = $struct['object']; if (is_string($object)) { // This is really a PHID, so look it up. $object_phid = $object; if (empty($ref_objects[$object_phid])) { // We weren't able to load the corresponding object, so just // reject this result outright. $reject = $extended_objects[$key]; unset($extended_objects[$key]); // TODO: This could be friendlier. $this->rejectObject($reject, false, '<bad-ref>'); continue; } $object = $ref_objects[$object_phid]; } $phid = $object->getPHID(); $key_map[$phid][] = $extended_key; $objects_in[$phid] = $object; } if ($objects_in) { $objects_out = id(new PhabricatorPolicyFilter())->setViewer($viewer)->requireCapabilities($capabilities)->apply($objects_in); $objects_out = mpull($objects_out, null, 'getPHID'); } else { $objects_out = array(); } // If any objects were removed by filtering, we're going to reject all // of the original objects which needed them. foreach ($objects_in as $phid => $object_in) { if (isset($objects_out[$phid])) { // This object survived filtering, so we don't need to throw any // results away. continue; } foreach ($key_map[$phid] as $extended_key) { if (empty($extended_objects[$extended_key])) { // We've already rejected this object, so we don't need to reject // it again. continue; } $reject = $extended_objects[$extended_key]; unset($extended_objects[$extended_key]); // TODO: This isn't as user-friendly as it could be. It's possible // that we're rejecting this object for multiple capability/policy // failures, though. $this->rejectObject($reject, false, '<extended>'); } } } return $extended_objects; }
public function attachRelationships(array $relationships) { $this->relationships = igroup($relationships, 'relation'); return $this; }
public function loadAvgs() { $limit = 1000; $conn_r = id(new DifferentialRevision())->establishConnection('r'); $sums = array(); $counts = array(); $all_not_reviewed = array(); $last_id = 0; do { $where = ''; if ($this->until !== null) { $where .= qsprintf($conn_r, ' AND dateCreated < %d', $this->until); } if ($this->since) { $where .= qsprintf($conn_r, ' AND (dateModified > %d OR status = %s)', $this->since, ArcanistDifferentialRevisionStatus::NEEDS_REVIEW); } $revisions = id(new DifferentialRevision())->loadAllWhere('id > %d%Q ORDER BY id LIMIT %d', $last_id, $where, $limit); if (!$revisions) { break; } $last_id = last_key($revisions); $relations = queryfx_all($conn_r, 'SELECT * FROM %T WHERE revisionID IN (%Ld) AND relation = %s', DifferentialRevision::RELATIONSHIP_TABLE, array_keys($revisions), DifferentialRevision::RELATION_REVIEWER); $relations = igroup($relations, 'revisionID'); $where = ''; if ($this->until !== null) { $where = qsprintf($conn_r, ' AND dateCreated < %d', $this->until); } $all_comments = id(new DifferentialComment())->loadAllWhere('revisionID IN (%Ld)%Q ORDER BY revisionID, id', array_keys($revisions), $where); $all_comments = mgroup($all_comments, 'getRevisionID'); foreach ($revisions as $id => $revision) { $revision->attachRelationships(idx($relations, $id, array())); $comments = idx($all_comments, $id, array()); list($reviewed, $not_reviewed) = $this->computeTimes($revision, $comments); foreach ($reviewed as $phid => $times) { $sums[$phid] = idx($sums, $phid, 0) + array_sum($times); $counts[$phid] = idx($counts, $phid, 0) + count($times); } foreach ($not_reviewed as $phid => $times) { $all_not_reviewed[$phid][] = $times; } } } while (count($revisions) >= $limit); foreach ($all_not_reviewed as $phid => $not_reviewed) { if (!array_key_exists($phid, $counts)) { // If the person didn't make any reviews than take maximum time because // he is at least that slow. $sums[$phid] = max(array_map('max', $not_reviewed)); $counts[$phid] = 1; continue; } $avg = $sums[$phid] / $counts[$phid]; foreach ($not_reviewed as $times) { foreach ($times as $time) { // Don't shorten the average time just because the reviewer was lucky // to be in a group with someone faster. if ($time > $avg) { $sums[$phid] += $time; $counts[$phid]++; } } } } $avgs = array(); foreach ($sums as $phid => $sum) { $avgs[$phid] = $sum / $counts[$phid]; } return $avgs; }
protected function getMethodFilters() { $classes = $this->getAllMethodImplementationClasses(); $method_names = array(); foreach ($classes as $method_class) { $method_name = ConduitAPIMethod::getAPIMethodNameFromClassName($method_class); $group_name = head(explode('.', $method_name)); $method_object = newv($method_class, array()); $status = $method_object->getMethodStatus(); $key = sprintf('%02d %s %s', $this->getOrderForMethodStatus($status), $group_name, $method_name); $method_names[$key] = array('full_name' => $method_name, 'group_name' => $group_name, 'status' => $status, 'description' => $method_object->getMethodDescription()); } ksort($method_names); $method_names = igroup($method_names, 'group_name'); ksort($method_names); return $method_names; }
private function loadDiffIDs($conn_r, array $revisions) { assert_instances_of($revisions, 'DifferentialRevision'); $diff_table = new DifferentialDiff(); $diff_ids = queryfx_all($conn_r, 'SELECT revisionID, id FROM %T WHERE revisionID IN (%Ld) ORDER BY id DESC', $diff_table->getTableName(), mpull($revisions, 'getID')); $diff_ids = igroup($diff_ids, 'revisionID'); foreach ($revisions as $revision) { $ids = idx($diff_ids, $revision->getID(), array()); $ids = ipull($ids, 'id'); $revision->attachDiffIDs($ids); } }
private function getRevisionProperties(DifferentialRevision $revision, DifferentialDiff $diff, array $handles, array $diff_properties) { $properties = array(); $status = $revision->getStatus(); $next_step = null; if ($status == DifferentialRevisionStatus::ACCEPTED) { switch ($diff->getSourceControlSystem()) { case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: $next_step = 'arc amend --revision ' . $revision->getID(); break; case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: $next_step = 'arc commit --revision ' . $revision->getID(); break; } if ($next_step) { $next_step = ' · ' . 'Next step: <tt>' . phutil_escape_html($next_step) . '</tt>'; } } $status = DifferentialRevisionStatus::getNameForRevisionStatus($status); $properties['Revision Status'] = '<strong>' . $status . '</strong>' . $next_step; $author = $handles[$revision->getAuthorPHID()]; $properties['Author'] = $author->renderLink(); $properties['Reviewers'] = $this->renderHandleLinkList(array_select_keys($handles, $revision->getReviewers())); $properties['CCs'] = $this->renderHandleLinkList(array_select_keys($handles, $revision->getCCPHIDs())); $host = $diff->getSourceMachine(); if ($host) { $properties['Host'] = phutil_escape_html($host); } $path = $diff->getSourcePath(); if ($path) { $branch = $diff->getBranch() ? ' (' . $diff->getBranch() . ')' : ''; $properties['Path'] = phutil_escape_html("{$path} {$branch}"); } $lstar = DifferentialRevisionUpdateHistoryView::renderDiffLintStar($diff); $lmsg = DifferentialRevisionUpdateHistoryView::getDiffLintMessage($diff); $ldata = idx($diff_properties, 'arc:lint'); $ltail = null; if ($ldata) { $ldata = igroup($ldata, 'path'); $lint_messages = array(); foreach ($ldata as $path => $messages) { $message_markup = array(); foreach ($messages as $message) { $path = idx($message, 'path'); $line = idx($message, 'line'); $code = idx($message, 'code'); $severity = idx($message, 'severity'); $name = idx($message, 'name'); $description = idx($message, 'description'); $message_markup[] = '<li>' . '<span class="lint-severity-' . phutil_escape_html($severity) . '">' . phutil_escape_html(ucwords($severity)) . '</span>' . ' ' . '(' . phutil_escape_html($code) . ') ' . phutil_escape_html($name) . ' at line ' . phutil_escape_html($line) . '<p>' . phutil_escape_html($description) . '</p>' . '</li>'; } $lint_messages[] = '<li class="lint-file-block">' . 'Lint for <strong>' . phutil_escape_html($path) . '</strong>' . '<ul>' . implode("\n", $message_markup) . '</ul>' . '</li>'; } $ltail = '<div class="differential-lint-block">' . '<ul>' . implode("\n", $lint_messages) . '</ul>' . '</div>'; } $properties['Lint'] = $lstar . ' ' . $lmsg . $ltail; $ustar = DifferentialRevisionUpdateHistoryView::renderDiffUnitStar($diff); $umsg = DifferentialRevisionUpdateHistoryView::getDiffUnitMessage($diff); $postponed_count = 0; $udata = idx($diff_properties, 'arc:unit'); $utail = null; if ($udata) { $unit_messages = array(); foreach ($udata as $test) { $name = phutil_escape_html(idx($test, 'name')); $result = phutil_escape_html(idx($test, 'result')); if ($result != DifferentialUnitTestResult::RESULT_POSTPONED && $result != DifferentialUnitTestResult::RESULT_PASS) { $userdata = phutil_escape_html(idx($test, 'userdata')); if (strlen($userdata) > 256) { $userdata = substr($userdata, 0, 256) . '...'; } $userdata = str_replace("\n", '<br />', $userdata); $unit_messages[] = '<tr>' . '<th>' . $name . '</th>' . '<th class="unit-test-result">' . '<div class="result-' . $result . '">' . strtoupper($result) . '</div>' . '</th>' . '<td>' . $userdata . '</td>' . '</tr>'; $utail = '<div class="differential-unit-block">' . '<table class="differential-unit-table">' . implode("\n", $unit_messages) . '</table>' . '</div>'; } else { if ($result == DifferentialUnitTestResult::RESULT_POSTPONED) { $postponed_count++; } } } } if ($postponed_count > 0 && $diff->getUnitStatus() == DifferentialUnitStatus::UNIT_POSTPONED) { $umsg = $postponed_count . ' ' . $umsg; } $properties['Unit'] = $ustar . ' ' . $umsg . $utail; if (PhabricatorEnv::getEnvConfig('maniphest.enabled')) { $tasks = $revision->getAttachedPHIDs(PhabricatorPHIDConstants::PHID_TYPE_TASK); if ($tasks) { $links = array(); foreach ($tasks as $task_phid) { $links[] = $handles[$task_phid]->renderLink(); } $properties['Maniphest Tasks'] = implode('<br />', $links); } } $commit_phids = $revision->getCommitPHIDs(); if ($commit_phids) { $links = array(); foreach ($commit_phids as $commit_phid) { $links[] = $handles[$commit_phid]->renderLink(); } $properties['Commits'] = implode('<br />', $links); } $properties['Lines'] = number_format($diff->getLineCount()); $arcanist_phid = $diff->getArcanistProjectPHID(); if ($arcanist_phid) { $properties['Arcanist Project'] = phutil_escape_html($handles[$arcanist_phid]->getName()); } $properties['Apply Patch'] = '<tt>arc patch D' . $revision->getID() . '</tt>'; $properties['Export Patch'] = '<tt>arc export --revision ' . $revision->getID() . '</tt>'; return $properties; }
public function renderValueForRevisionView() { $diff = $this->getDiff(); $path_changesets = mpull($diff->loadChangesets(), 'getID', 'getFilename'); $lstar = DifferentialRevisionUpdateHistoryView::renderDiffLintStar($diff); $lmsg = DifferentialRevisionUpdateHistoryView::getDiffLintMessage($diff); $ldata = $this->getDiffProperty('arc:lint'); $ltail = null; $rows = array(); $rows[] = array('style' => 'star', 'name' => $lstar, 'value' => $lmsg, 'show' => true); $excuse = $this->getLintExcuse(); if ($excuse) { $rows[] = array('style' => 'excuse', 'name' => 'Excuse', 'value' => nl2br(phutil_escape_html($excuse)), 'show' => true); } $show_limit = 10; $hidden = array(); if ($ldata) { $ldata = igroup($ldata, 'path'); foreach ($ldata as $path => $messages) { $rows[] = array('style' => 'section', 'name' => phutil_escape_html($path), 'show' => $show_limit); foreach ($messages as $message) { $path = idx($message, 'path'); $line = idx($message, 'line'); $code = idx($message, 'code'); $severity = idx($message, 'severity'); $name = idx($message, 'name'); $description = idx($message, 'description'); $line_link = 'line ' . intval($line); if (isset($path_changesets[$path])) { $line_link = phutil_render_tag('a', array('href' => '#C' . $path_changesets[$path] . 'NL' . max(1, $line)), $line_link); } if ($show_limit) { --$show_limit; $show = true; } else { $show = false; if (empty($hidden[$severity])) { $hidden[$severity] = 0; } $hidden[$severity]++; } $rows[] = array('style' => $this->getSeverityStyle($severity), 'name' => phutil_escape_html(ucwords($severity)), 'value' => hsprintf("(%s) %s at {$line_link}", $code, $name), 'show' => $show); if (strlen($description)) { $rows[] = array('style' => 'details', 'value' => nl2br(phutil_escape_html($description)), 'show' => false); if (empty($hidden['details'])) { $hidden['details'] = 0; } $hidden['details']++; } } } } $postponed = $this->getPostponedLinters(); if ($postponed) { foreach ($postponed as $linter) { $rows[] = array('style' => $this->getPostponedStyle(), 'name' => 'Postponed', 'value' => phutil_escape_html($linter), 'show' => false); if (empty($hidden['postponed'])) { $hidden['postponed'] = 0; } $hidden['postponed']++; } } $show_string = $this->renderShowString($hidden); $view = new DifferentialResultsTableView(); $view->setRows($rows); $view->setShowMoreString($show_string); return $view->render(); }
protected function renderInput() { if (!$this->object) { throw new PhutilInvalidStateException('setPolicyObject'); } if (!$this->capability) { throw new PhutilInvalidStateException('setCapability'); } $policy = $this->object->getPolicy($this->capability); if (!$policy) { // TODO: Make this configurable. $policy = PhabricatorPolicies::POLICY_USER; } if (!$this->getValue()) { $this->setValue($policy); } $control_id = celerity_generate_unique_node_id(); $input_id = celerity_generate_unique_node_id(); $caret = phutil_tag('span', array('class' => 'caret')); $input = phutil_tag('input', array('type' => 'hidden', 'id' => $input_id, 'name' => $this->getName(), 'value' => $this->getValue())); $options = $this->getOptions(); $order = array(); $labels = array(); foreach ($options as $key => $values) { $order[$key] = array_keys($values); $labels[$key] = PhabricatorPolicyType::getPolicyTypeName($key); } $flat_options = array_mergev($options); $icons = array(); foreach (igroup($flat_options, 'icon') as $icon => $ignored) { $icons[$icon] = id(new PHUIIconView())->setIconFont($icon); } if ($this->templatePHIDType) { $context_path = 'template/' . $this->templatePHIDType . '/'; } else { $object_phid = $this->object->getPHID(); if ($object_phid) { $context_path = 'object/' . $object_phid . '/'; } else { $object_type = phid_get_type($this->object->generatePHID()); $context_path = 'type/' . $object_type . '/'; } } Javelin::initBehavior('policy-control', array('controlID' => $control_id, 'inputID' => $input_id, 'options' => $flat_options, 'groups' => array_keys($options), 'order' => $order, 'icons' => $icons, 'labels' => $labels, 'value' => $this->getValue(), 'capability' => $this->capability, 'editURI' => '/policy/edit/' . $context_path, 'customPlaceholder' => $this->getCustomPolicyPlaceholder(), 'disabled' => $this->getDisabled())); $selected = idx($flat_options, $this->getValue(), array()); $selected_icon = idx($selected, 'icon'); $selected_name = idx($selected, 'name'); $spaces_control = $this->buildSpacesControl(); return phutil_tag('div', array(), array($spaces_control, javelin_tag('a', array('class' => 'grey button dropdown has-icon policy-control', 'href' => '#', 'mustcapture' => true, 'sigil' => 'policy-control', 'id' => $control_id), array($caret, javelin_tag('span', array('sigil' => 'policy-label', 'class' => 'phui-button-text'), array(idx($icons, $selected_icon), $selected_name)))), $input)); return AphrontFormSelectControl::renderSelectTag($this->getValue(), $this->getOptions(), array('name' => $this->getName(), 'disabled' => $this->getDisabled() ? 'disabled' : null, 'id' => $this->getID())); }
public function loadActualSchema() { $databases = $this->getDatabaseNames(); $conn = $this->getConn(); $tables = queryfx_all($conn, 'SELECT TABLE_SCHEMA, TABLE_NAME, TABLE_COLLATION FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA IN (%Ls)', $databases); $database_info = queryfx_all($conn, 'SELECT SCHEMA_NAME, DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME IN (%Ls)', $databases); $database_info = ipull($database_info, null, 'SCHEMA_NAME'); // Find databases which exist, but which the user does not have permission // to see. $invisible_databases = array(); foreach ($databases as $database_name) { if (isset($database_info[$database_name])) { continue; } try { queryfx($conn, 'SHOW TABLES IN %T', $database_name); } catch (AphrontAccessDeniedQueryException $ex) { // This database exists, the user just doesn't have permission to // see it. $invisible_databases[] = $database_name; } catch (AphrontSchemaQueryException $ex) { // This database is legitimately missing. } } $sql = array(); foreach ($tables as $table) { $sql[] = qsprintf($conn, '(TABLE_SCHEMA = %s AND TABLE_NAME = %s)', $table['TABLE_SCHEMA'], $table['TABLE_NAME']); } if ($sql) { $column_info = queryfx_all($conn, 'SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, CHARACTER_SET_NAME, COLLATION_NAME, COLUMN_TYPE, IS_NULLABLE, EXTRA FROM INFORMATION_SCHEMA.COLUMNS WHERE (%Q)', '(' . implode(') OR (', $sql) . ')'); $column_info = igroup($column_info, 'TABLE_SCHEMA'); } else { $column_info = array(); } // NOTE: Tables like KEY_COLUMN_USAGE and TABLE_CONSTRAINTS only contain // primary, unique, and foreign keys, so we can't use them here. We pull // indexes later on using SHOW INDEXES. $server_schema = new PhabricatorConfigServerSchema(); $tables = igroup($tables, 'TABLE_SCHEMA'); foreach ($tables as $database_name => $database_tables) { $info = $database_info[$database_name]; $database_schema = id(new PhabricatorConfigDatabaseSchema())->setName($database_name)->setCharacterSet($info['DEFAULT_CHARACTER_SET_NAME'])->setCollation($info['DEFAULT_COLLATION_NAME']); $database_column_info = idx($column_info, $database_name, array()); $database_column_info = igroup($database_column_info, 'TABLE_NAME'); foreach ($database_tables as $table) { $table_name = $table['TABLE_NAME']; $table_schema = id(new PhabricatorConfigTableSchema())->setName($table_name)->setCollation($table['TABLE_COLLATION']); $columns = idx($database_column_info, $table_name, array()); foreach ($columns as $column) { if (strpos($column['EXTRA'], 'auto_increment') === false) { $auto_increment = false; } else { $auto_increment = true; } $column_schema = id(new PhabricatorConfigColumnSchema())->setName($column['COLUMN_NAME'])->setCharacterSet($column['CHARACTER_SET_NAME'])->setCollation($column['COLLATION_NAME'])->setColumnType($column['COLUMN_TYPE'])->setNullable($column['IS_NULLABLE'] == 'YES')->setAutoIncrement($auto_increment); $table_schema->addColumn($column_schema); } $key_parts = queryfx_all($conn, 'SHOW INDEXES FROM %T.%T', $database_name, $table_name); $keys = igroup($key_parts, 'Key_name'); foreach ($keys as $key_name => $key_pieces) { $key_pieces = isort($key_pieces, 'Seq_in_index'); $head = head($key_pieces); // This handles string indexes which index only a prefix of a field. $column_names = array(); foreach ($key_pieces as $piece) { $name = $piece['Column_name']; if ($piece['Sub_part']) { $name = $name . '(' . $piece['Sub_part'] . ')'; } $column_names[] = $name; } $key_schema = id(new PhabricatorConfigKeySchema())->setName($key_name)->setColumnNames($column_names)->setUnique(!$head['Non_unique'])->setIndexType($head['Index_type']); $table_schema->addKey($key_schema); } $database_schema->addTable($table_schema); } $server_schema->addDatabase($database_schema); } foreach ($invisible_databases as $database_name) { $server_schema->addDatabase(id(new PhabricatorConfigDatabaseSchema())->setName($database_name)->setAccessDenied(true)); } return $server_schema; }
public function loadRelationships() { if (!$this->getID()) { $this->relationships = array(); return; } $data = queryfx_all($this->establishConnection('r'), 'SELECT * FROM %T WHERE revisionID = %d ORDER BY sequence', self::RELATIONSHIP_TABLE, $this->getID()); $this->relationships = igroup($data, 'relation'); return $this; }
/** * Remove queued edges. * * @task internal */ private function executeRemoves() { $rems = $this->remEdges; $rems = igroup($rems, 'src_type'); $deletes = array(); foreach ($rems as $src_type => $edges) { $conn_w = PhabricatorEdgeConfig::establishConnection($src_type, 'w'); $sql = array(); foreach ($edges as $edge) { $sql[] = qsprintf($conn_w, '(%s, %d, %s)', $edge['src'], $edge['type'], $edge['dst']); } $deletes[] = array($conn_w, $sql); } foreach ($deletes as $delete) { list($conn_w, $sql) = $delete; $conn_w->openTransaction(); $this->openTransactions[] = $conn_w; foreach (array_chunk($sql, 256) as $chunk) { queryfx($conn_w, 'DELETE FROM %T WHERE (src, type, dst) IN (%Q)', PhabricatorEdgeConfig::TABLE_NAME_EDGE, implode(', ', $chunk)); } } }
public function save() { if ($this->getID()) { $is_new = false; } else { $is_new = true; } $this->openTransaction(); $ret = parent::save(); $add_owners = array(); $remove_owners = array(); $all_owners = array(); if ($this->unsavedOwners) { $new_owners = array_fill_keys($this->unsavedOwners, true); $cur_owners = array(); foreach ($this->loadOwners() as $owner) { if (empty($new_owners[$owner->getUserPHID()])) { $remove_owners[$owner->getUserPHID()] = true; $owner->delete(); continue; } $cur_owners[$owner->getUserPHID()] = true; } $add_owners = array_diff_key($new_owners, $cur_owners); $all_owners = array_merge(array($this->getPrimaryOwnerPHID() => true), $new_owners, $remove_owners); foreach ($add_owners as $phid => $ignored) { $owner = new PhabricatorOwnersOwner(); $owner->setPackageID($this->getID()); $owner->setUserPHID($phid); $owner->save(); } unset($this->unsavedOwners); } $add_paths = array(); $remove_paths = array(); $touched_repos = array(); if ($this->unsavedPaths) { $new_paths = igroup($this->unsavedPaths, 'repositoryPHID', 'path'); $cur_paths = $this->loadPaths(); foreach ($cur_paths as $key => $path) { if (empty($new_paths[$path->getRepositoryPHID()][$path->getPath()])) { $touched_repos[$path->getRepositoryPHID()] = true; $remove_paths[$path->getRepositoryPHID()][$path->getPath()] = true; $path->delete(); unset($cur_paths[$key]); } } $cur_paths = mgroup($cur_paths, 'getRepositoryPHID', 'getPath'); foreach ($new_paths as $repository_phid => $paths) { // get repository object for path validation $repository = id(new PhabricatorRepository())->loadOneWhere('phid = %s', $repository_phid); if (!$repository) { continue; } foreach ($paths as $path => $ignored) { $path = ltrim($path, '/'); // build query to validate path $drequest = DiffusionRequest::newFromDictionary(array('repository' => $repository, 'path' => $path)); $query = DiffusionBrowseQuery::newFromDiffusionRequest($drequest); $query->needValidityOnly(true); $valid = $query->loadPaths(); $is_directory = true; if (!$valid) { switch ($query->getReasonForEmptyResultSet()) { case DiffusionBrowseQuery::REASON_IS_FILE: $valid = true; $is_directory = false; break; case DiffusionBrowseQuery::REASON_IS_EMPTY: $valid = true; break; } } if ($is_directory && substr($path, -1) != '/') { $path .= '/'; } if (substr($path, 0, 1) != '/') { $path = '/' . $path; } if (empty($cur_paths[$repository_phid][$path]) && $valid) { $touched_repos[$repository_phid] = true; $add_paths[$repository_phid][$path] = true; $obj = new PhabricatorOwnersPath(); $obj->setPackageID($this->getID()); $obj->setRepositoryPHID($repository_phid); $obj->setPath($path); $obj->save(); } } } unset($this->unsavedPaths); } $this->saveTransaction(); if ($is_new) { $mail = new PackageCreateMail($this); } else { $mail = new PackageModifyMail($this, array_keys($add_owners), array_keys($remove_owners), array_keys($all_owners), array_keys($touched_repos), $add_paths, $remove_paths); } $mail->send(); return $ret; }
public function renderPropertyViewValue(array $handles) { $diff = $this->getObject()->getActiveDiff(); $path_changesets = mpull($diff->loadChangesets(), 'getID', 'getFilename'); $lstar = DifferentialRevisionUpdateHistoryView::renderDiffLintStar($diff); $lmsg = DifferentialRevisionUpdateHistoryView::getDiffLintMessage($diff); $ldata = $diff->getProperty('arc:lint'); $ltail = null; $rows = array(); $rows[] = array('style' => 'star', 'name' => $lstar, 'value' => $lmsg, 'show' => true); $excuse = $diff->getProperty('arc:lint-excuse'); if ($excuse) { $rows[] = array('style' => 'excuse', 'name' => 'Excuse', 'value' => phutil_escape_html_newlines($excuse), 'show' => true); } $show_limit = 10; $hidden = array(); if ($ldata) { $ldata = igroup($ldata, 'path'); foreach ($ldata as $path => $messages) { $rows[] = array('style' => 'section', 'name' => $path, 'show' => $show_limit); foreach ($messages as $message) { $path = idx($message, 'path'); $line = idx($message, 'line'); $code = idx($message, 'code'); $severity = idx($message, 'severity'); $name = idx($message, 'name'); $description = idx($message, 'description'); $line_link = 'line ' . intval($line); if (isset($path_changesets[$path])) { $href = '#C' . $path_changesets[$path] . 'NL' . max(1, $line); // TODO: We are always showing the active diff // if ($diff->getID() != $this->getDiff()->getID()) { // $href = '/D'.$diff->getRevisionID().'?id='.$diff->getID().$href; // } $line_link = phutil_tag('a', array('href' => $href), $line_link); } if ($show_limit) { --$show_limit; $show = true; } else { $show = false; if (empty($hidden[$severity])) { $hidden[$severity] = 0; } $hidden[$severity]++; } $rows[] = array('style' => $this->getSeverityStyle($severity), 'name' => ucwords($severity), 'value' => hsprintf('(%s) %s at %s', $code, $name, $line_link), 'show' => $show); if (!empty($message['locations'])) { $locations = array(); foreach ($message['locations'] as $location) { $other_line = idx($location, 'line'); $locations[] = idx($location, 'path', $path) . ($other_line ? ":{$other_line}" : ''); } $description .= "\nOther locations: " . implode(', ', $locations); } if (strlen($description)) { $rows[] = array('style' => 'details', 'value' => phutil_escape_html_newlines($description), 'show' => false); if (empty($hidden['details'])) { $hidden['details'] = 0; } $hidden['details']++; } } } } $postponed = $diff->getProperty('arc:lint-postponed'); if ($postponed) { foreach ($postponed as $linter) { $rows[] = array('style' => $this->getPostponedStyle(), 'name' => 'Postponed', 'value' => $linter, 'show' => false); if (empty($hidden['postponed'])) { $hidden['postponed'] = 0; } $hidden['postponed']++; } } $show_string = $this->renderShowString($hidden); $view = new DifferentialResultsTableView(); $view->setRows($rows); $view->setShowMoreString($show_string); return $view->render(); }
public function save() { // TODO: Transactions! $ret = parent::save(); if ($this->unsavedOwners) { $new_owners = array_fill_keys($this->unsavedOwners, true); $cur_owners = array(); foreach ($this->loadOwners() as $owner) { if (empty($new_owners[$owner->getUserPHID()])) { $owner->delete(); continue; } $cur_owners[$owner->getUserPHID()] = true; } $add_owners = array_diff_key($new_owners, $cur_owners); foreach ($add_owners as $phid => $ignored) { $owner = new PhabricatorOwnersOwner(); $owner->setPackageID($this->getID()); $owner->setUserPHID($phid); $owner->save(); } unset($this->unsavedOwners); } if ($this->unsavedPaths) { $new_paths = igroup($this->unsavedPaths, 'repositoryPHID', 'path'); $cur_paths = $this->loadPaths(); foreach ($cur_paths as $key => $path) { if (empty($new_paths[$path->getRepositoryPHID()][$path->getPath()])) { $path->delete(); unset($cur_paths[$key]); } } $cur_paths = mgroup($cur_paths, 'getRepositoryPHID', 'getPath'); foreach ($new_paths as $repository_phid => $paths) { foreach ($paths as $path => $ignored) { if (empty($cur_paths[$repository_phid][$path])) { $obj = new PhabricatorOwnersPath(); $obj->setPackageID($this->getID()); $obj->setRepositoryPHID($repository_phid); $obj->setPath($path); $obj->save(); } } } unset($this->unsavedPaths); } return $ret; }
public function testIGroup() { $apple = ['name' => 'Apple', 'type' => 'fruit', 'colour' => 'green', 'group' => 'food']; $bear = ['name' => 'Bear', 'type' => 'animal', 'colour' => 'brown', 'group' => 'creature']; $carrot = ['name' => 'Carrot', 'type' => 'vegetable', 'colour' => 'brown', 'group' => 'food']; $list = ['a' => $apple, 'b' => $bear, 'c' => $carrot]; $expect = ['fruit' => ['a' => $apple], 'animal' => ['b' => $bear], 'vegetable' => ['c' => $carrot]]; $this->assertEquals($expect, igroup($list, 'type')); $expect = ['food' => ['fruit' => ['a' => $apple], 'vegetable' => ['c' => $carrot]], 'creature' => ['animal' => ['b' => $bear]]]; $this->assertEquals($expect, igroup($list, 'group', 'type')); $expect = ['food' => ['a' => $apple, 'c' => $carrot], 'creature' => ['b' => $bear]]; $this->assertEquals($expect, igroup($list, 'group')); }
/** * Rebuild a cache bucket, amending existing data if available. * * @param int Bucket key, from @{method:getBucketKey}. * @param array Existing bucket data. * @return array Rebuilt bucket data. * @task cache */ private function rebuildBucket($bucket_key, array $current_data) { // First, check if we've already rebuilt this bucket. In some cases (like // browsing a repository at some commit) it's common to issue many lookups // against one commit. If that commit has been discovered but not yet // fully imported, we'll repeatedly attempt to rebuild the bucket. If the // first rebuild did not work, subsequent rebuilds are very unlikely to // have any effect. We can just skip the rebuild in these cases. if (isset($this->rebuiltKeys[$bucket_key])) { return $current_data; } else { $this->rebuiltKeys[$bucket_key] = true; } $bucket_min = $bucket_key * $this->getBucketSize(); $bucket_max = $bucket_min + $this->getBucketSize() - 1; // We need to reload all of the commits in the bucket because there is // no guarantee that they'll get parsed in order, so we can fill large // commit IDs before small ones. Later on, we'll ignore the commits we // already know about. $table_commit = new PhabricatorRepositoryCommit(); $table_repository = new PhabricatorRepository(); $conn_r = $table_commit->establishConnection('r'); // Find all the Git and Mercurial commits in the block which have completed // change import. We can't fill the cache accurately for commits which have // not completed change import, so just pretend we don't know about them. // In these cases, we will ultimately fall back to VCS queries. $commit_rows = queryfx_all($conn_r, 'SELECT c.id FROM %T c JOIN %T r ON c.repositoryID = r.id AND r.versionControlSystem IN (%Ls) WHERE c.id BETWEEN %d AND %d AND (c.importStatus & %d) = %d', $table_commit->getTableName(), $table_repository->getTableName(), array(PhabricatorRepositoryType::REPOSITORY_TYPE_GIT, PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL), $bucket_min, $bucket_max, PhabricatorRepositoryCommit::IMPORTED_CHANGE, PhabricatorRepositoryCommit::IMPORTED_CHANGE); // If we don't have any data, just return the existing data. if (!$commit_rows) { return $current_data; } // Remove the commits we already have data for. We don't need to rebuild // these. If there's nothing left, return the existing data. $commit_ids = ipull($commit_rows, 'id', 'id'); $commit_ids = array_diff_key($commit_ids, $current_data); if (!$commit_ids) { return $current_data; } // Find all the path changes for the new commits. $path_changes = queryfx_all($conn_r, 'SELECT commitID, pathID FROM %T WHERE commitID IN (%Ld) AND (isDirect = 1 OR changeType = %d)', PhabricatorRepository::TABLE_PATHCHANGE, $commit_ids, DifferentialChangeType::TYPE_CHILD); $path_changes = igroup($path_changes, 'commitID'); // Find all the parents for the new commits. $parents = queryfx_all($conn_r, 'SELECT childCommitID, parentCommitID FROM %T WHERE childCommitID IN (%Ld) ORDER BY id ASC', PhabricatorRepository::TABLE_PARENTS, $commit_ids); $parents = igroup($parents, 'childCommitID'); // Build the actual data for the cache. foreach ($commit_ids as $commit_id) { $parent_ids = array(); if (!empty($parents[$commit_id])) { foreach ($parents[$commit_id] as $row) { $parent_ids[] = (int) $row['parentCommitID']; } } else { // We expect all rows to have parents (commits with no parents get // an explicit "0" placeholder). If we're in an older repository, the // parent information might not have been populated yet. Decline to fill // the cache if we don't have the parent information, since the fill // will be incorrect. continue; } if (isset($path_changes[$commit_id])) { $path_ids = $path_changes[$commit_id]; foreach ($path_ids as $key => $path_id) { $path_ids[$key] = (int) $path_id['pathID']; } sort($path_ids); } else { $path_ids = array(); } $value = $parent_ids; $value[] = null; foreach ($path_ids as $path_id) { $value[] = $path_id; } $current_data[$commit_id] = $value; } return $current_data; }
private function getMethodFilters() { $classes = $this->getAllMethodImplementationClasses(); $method_names = array(); foreach ($classes as $method_class) { $method_name = ConduitAPIMethod::getAPIMethodNameFromClassName($method_class); $parts = explode('.', $method_name); $method_names[] = array('full_name' => $method_name, 'group_name' => reset($parts)); } $method_names = igroup($method_names, 'group_name'); ksort($method_names); return $method_names; }
private function fillUserCaches(array $users) { if (!$this->cacheKeys) { return; } $user_map = mpull($users, null, 'getPHID'); $keys = array_keys($this->cacheKeys); $hashes = array(); foreach ($keys as $key) { $hashes[] = PhabricatorHash::digestForIndex($key); } $types = PhabricatorUserCacheType::getAllCacheTypes(); // First, pull any available caches. If we wanted to be particularly clever // we could do this with JOINs in the main query. $cache_table = new PhabricatorUserCache(); $cache_conn = $cache_table->establishConnection('r'); $cache_data = queryfx_all($cache_conn, 'SELECT cacheKey, userPHID, cacheData, cacheType FROM %T WHERE cacheIndex IN (%Ls) AND userPHID IN (%Ls)', $cache_table->getTableName(), $hashes, array_keys($user_map)); $skip_validation = array(); // After we read caches from the database, discard any which have data that // invalid or out of date. This allows cache types to implement TTLs or // versions instead of or in addition to explicit cache clears. foreach ($cache_data as $row_key => $row) { $cache_type = $row['cacheType']; if (isset($skip_validation[$cache_type])) { continue; } if (empty($types[$cache_type])) { unset($cache_data[$row_key]); continue; } $type = $types[$cache_type]; if (!$type->shouldValidateRawCacheData()) { $skip_validation[$cache_type] = true; continue; } $user = $user_map[$row['userPHID']]; $raw_data = $row['cacheData']; if (!$type->isRawCacheDataValid($user, $row['cacheKey'], $raw_data)) { unset($cache_data[$row_key]); continue; } } $need = array(); $cache_data = igroup($cache_data, 'userPHID'); foreach ($user_map as $user_phid => $user) { $raw_rows = idx($cache_data, $user_phid, array()); $raw_data = ipull($raw_rows, 'cacheData', 'cacheKey'); foreach ($keys as $key) { if (isset($raw_data[$key]) || array_key_exists($key, $raw_data)) { continue; } $need[$key][$user_phid] = $user; } $user->attachRawCacheData($raw_data); } // If we missed any cache values, bulk-construct them now. This is // usually much cheaper than generating them on-demand for each user // record. if (!$need) { return; } $writes = array(); foreach ($need as $cache_key => $need_users) { $type = PhabricatorUserCacheType::getCacheTypeForKey($cache_key); if (!$type) { continue; } $data = $type->newValueForUsers($cache_key, $need_users); foreach ($data as $user_phid => $raw_value) { $data[$user_phid] = $raw_value; $writes[] = array('userPHID' => $user_phid, 'key' => $cache_key, 'type' => $type, 'value' => $raw_value); } foreach ($need_users as $user_phid => $user) { if (isset($data[$user_phid]) || array_key_exists($user_phid, $data)) { $user->attachRawCacheData(array($cache_key => $data[$user_phid])); } } } PhabricatorUserCache::writeCaches($writes); }
public static function findLongestPathsPerPackage(array $rows, array $paths) { $ids = array(); foreach (igroup($rows, 'id') as $id => $package_paths) { $relevant_paths = array_select_keys($paths, ipull($package_paths, 'path')); // For every package, remove all excluded paths. $remove = array(); foreach ($package_paths as $package_path) { if ($package_path['excluded']) { $remove += idx($relevant_paths, $package_path['path'], array()); unset($relevant_paths[$package_path['path']]); } } if ($remove) { foreach ($relevant_paths as $fragment => $fragment_paths) { $relevant_paths[$fragment] = array_diff_key($fragment_paths, $remove); } } $relevant_paths = array_filter($relevant_paths); if ($relevant_paths) { $ids[$id] = max(array_map('strlen', array_keys($relevant_paths))); } } return $ids; }
public function handleRequest(AphrontRequest $request) { $viewer = $request->getUser(); $book_name = $request->getURIData('book'); $atom_type = $request->getURIData('type'); $atom_name = $request->getURIData('name'); $atom_context = nonempty($request->getURIData('context'), null); $atom_index = nonempty($request->getURIData('index'), null); require_celerity_resource('diviner-shared-css'); $book = id(new DivinerBookQuery())->setViewer($viewer)->withNames(array($book_name))->executeOne(); if (!$book) { return new Aphront404Response(); } $symbol = id(new DivinerAtomQuery())->setViewer($viewer)->withBookPHIDs(array($book->getPHID()))->withTypes(array($atom_type))->withNames(array($atom_name))->withContexts(array($atom_context))->withIndexes(array($atom_index))->withIsDocumentable(true)->needAtoms(true)->needExtends(true)->needChildren(true)->executeOne(); if (!$symbol) { return new Aphront404Response(); } $atom = $symbol->getAtom(); $crumbs = $this->buildApplicationCrumbs(); $crumbs->setBorder(true); $crumbs->addTextCrumb($book->getShortTitle(), '/book/' . $book->getName() . '/'); $atom_short_title = $atom ? $atom->getDocblockMetaValue('short', $symbol->getTitle()) : $symbol->getTitle(); $crumbs->addTextCrumb($atom_short_title); $header = id(new PHUIHeaderView())->setHeader($this->renderFullSignature($symbol)); $properties = new PHUIPropertyListView(); $group = $atom ? $atom->getProperty('group') : $symbol->getGroupName(); if ($group) { $group_name = $book->getGroupName($group); } else { $group_name = null; } $prop_list = new PHUIPropertyGroupView(); $prop_list->addPropertyList($properties); $document = id(new PHUIDocumentViewPro())->setBook($book->getTitle(), $group_name)->setHeader($header)->addClass('diviner-view'); if ($atom) { $this->buildDefined($properties, $symbol); $this->buildExtendsAndImplements($properties, $symbol); $this->buildRepository($properties, $symbol); $warnings = $atom->getWarnings(); if ($warnings) { $warnings = id(new PHUIInfoView())->setErrors($warnings)->setTitle(pht('Documentation Warnings'))->setSeverity(PHUIInfoView::SEVERITY_WARNING); } $document->appendChild($warnings); } $methods = $this->composeMethods($symbol); $field = 'default'; $engine = id(new PhabricatorMarkupEngine())->setViewer($viewer)->addObject($symbol, $field); foreach ($methods as $method) { foreach ($method['atoms'] as $matom) { $engine->addObject($matom, $field); } } $engine->process(); if ($atom) { $content = $this->renderDocumentationText($symbol, $engine); $document->appendChild($content); } $toc = $engine->getEngineMetadata($symbol, $field, PhutilRemarkupHeaderBlockRule::KEY_HEADER_TOC, array()); if (!$atom) { $document->appendChild(id(new PHUIInfoView())->setSeverity(PHUIInfoView::SEVERITY_NOTICE)->appendChild(pht('This atom no longer exists.'))); } if ($atom) { $document->appendChild($this->buildParametersAndReturn(array($symbol))); } if ($methods) { $tasks = $this->composeTasks($symbol); if ($tasks) { $methods_by_task = igroup($methods, 'task'); // Add phantom tasks for methods which have a "@task" name that isn't // documented anywhere, or methods that have no "@task" name. foreach ($methods_by_task as $task => $ignored) { if (empty($tasks[$task])) { $tasks[$task] = array('name' => $task, 'title' => $task ? $task : pht('Other Methods'), 'defined' => $symbol); } } $section = id(new DivinerSectionView())->setHeader(pht('Tasks')); foreach ($tasks as $spec) { $section->addContent(id(new PHUIHeaderView())->setNoBackground(true)->setHeader($spec['title'])); $task_methods = idx($methods_by_task, $spec['name'], array()); $box_content = array(); if ($task_methods) { $list_items = array(); foreach ($task_methods as $task_method) { $atom = last($task_method['atoms']); $item = $this->renderFullSignature($atom, true); if (strlen($atom->getSummary())) { $item = array($item, " — ", $atom->getSummary()); } $list_items[] = phutil_tag('li', array(), $item); } $box_content[] = phutil_tag('ul', array('class' => 'diviner-list'), $list_items); } else { $no_methods = pht('No methods for this task.'); $box_content = phutil_tag('em', array(), $no_methods); } $inner_box = phutil_tag_div('diviner-task-items', $box_content); $section->addContent($inner_box); } $document->appendChild($section); } $section = id(new DivinerSectionView())->setHeader(pht('Methods')); foreach ($methods as $spec) { $matom = last($spec['atoms']); $method_header = id(new PHUIHeaderView())->setNoBackground(true); $inherited = $spec['inherited']; if ($inherited) { $method_header->addTag(id(new PHUITagView())->setType(PHUITagView::TYPE_STATE)->setBackgroundColor(PHUITagView::COLOR_GREY)->setName(pht('Inherited'))); } $method_header->setHeader($this->renderFullSignature($matom)); $section->addContent(array($method_header, $this->renderMethodDocumentationText($symbol, $spec, $engine), $this->buildParametersAndReturn($spec['atoms']))); } $document->appendChild($section); } if ($toc) { $side = new PHUIListView(); $side->addMenuItem(id(new PHUIListItemView())->setName(pht('Contents'))->setType(PHUIListItemView::TYPE_LABEL)); foreach ($toc as $key => $entry) { $side->addMenuItem(id(new PHUIListItemView())->setName($entry[1])->setHref('#' . $key)); } $document->setToc($side); } $prop_list = phutil_tag_div('phui-document-view-pro-box', $prop_list); return $this->newPage()->setTitle($symbol->getTitle())->setCrumbs($crumbs)->appendChild(array($document, $prop_list)); }