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);
 }
Ejemplo n.º 7
0
 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;
 }
Ejemplo n.º 8
0
 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;
 }
Ejemplo n.º 11
0
 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 = ' &middot; ' . '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();
 }
Ejemplo n.º 17
0
 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;
 }
Ejemplo n.º 20
0
 /**
  * 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));
         }
     }
 }
Ejemplo n.º 21
0
 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;
 }
Ejemplo n.º 24
0
 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);
 }
Ejemplo n.º 28
0
 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;
 }
Ejemplo n.º 29
0
 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));
 }