Path: blob/master/src/applications/config/controller/PhabricatorConfigConsoleController.php
12256 views
<?php12final class PhabricatorConfigConsoleController3extends PhabricatorConfigController {45public function handleRequest(AphrontRequest $request) {6$viewer = $request->getViewer();78$menu = id(new PHUIObjectItemListView())9->setViewer($viewer)10->setBig(true);1112$menu->addItem(13id(new PHUIObjectItemView())14->setHeader(pht('Settings'))15->setHref($this->getApplicationURI('settings/'))16->setImageIcon('fa-wrench')17->setClickable(true)18->addAttribute(19pht(20'Review and modify configuration settings.')));2122$menu->addItem(23id(new PHUIObjectItemView())24->setHeader(pht('Setup Issues'))25->setHref($this->getApplicationURI('issue/'))26->setImageIcon('fa-exclamation-triangle')27->setClickable(true)28->addAttribute(29pht(30'Show unresolved issues with setup and configuration.')));3132$menu->addItem(33id(new PHUIObjectItemView())34->setHeader(pht('Services'))35->setHref($this->getApplicationURI('cluster/databases/'))36->setImageIcon('fa-server')37->setClickable(true)38->addAttribute(39pht(40'View status information for databases, caches, repositories, '.41'and other services.')));4243$menu->addItem(44id(new PHUIObjectItemView())45->setHeader(pht('Extensions/Modules'))46->setHref($this->getApplicationURI('module/'))47->setImageIcon('fa-gear')48->setClickable(true)49->addAttribute(50pht(51'Show installed extensions and modules.')));5253$crumbs = $this->buildApplicationCrumbs()54->addTextCrumb(pht('Console'))55->setBorder(true);5657$box = id(new PHUIObjectBoxView())58->setHeaderText(pht('Configuration'))59->setBackground(PHUIObjectBoxView::WHITE_CONFIG)60->setObjectList($menu);6162$versions = $this->newLibraryVersionTable($viewer);63$binary_versions = $this->newBinaryVersionTable();6465$launcher_view = id(new PHUILauncherView())66->appendChild($box)67->appendChild($versions)68->appendChild($binary_versions);6970$view = id(new PHUITwoColumnView())71->setFooter($launcher_view);7273return $this->newPage()74->setTitle(pht('Configuration'))75->setCrumbs($crumbs)76->appendChild($view);77}7879public function newLibraryVersionTable() {80$viewer = $this->getViewer();8182$versions = $this->loadVersions($viewer);8384$rows = array();85foreach ($versions as $name => $info) {86$branchpoint = $info['branchpoint'];87if ($branchpoint !== null && strlen($branchpoint)) {88$branchpoint = substr($branchpoint, 0, 12);89} else {90$branchpoint = null;91}9293$version = $info['hash'];94if ($version !== null && strlen($version)) {95$version = substr($version, 0, 12);96} else {97$version = pht('Unknown');98}99100101$epoch = $info['epoch'];102if ($epoch) {103$epoch = phabricator_date($epoch, $viewer);104} else {105$epoch = null;106}107108$rows[] = array(109$name,110$version,111$epoch,112$branchpoint,113);114}115116$table_view = id(new AphrontTableView($rows))117->setHeaders(118array(119pht('Library'),120pht('Version'),121pht('Date'),122pht('Branchpoint'),123))124->setColumnClasses(125array(126'pri',127null,128null,129'wide',130));131132return id(new PHUIObjectBoxView())133->setHeaderText(pht('Version Information'))134->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)135->appendChild($table_view);136}137138private function loadVersions(PhabricatorUser $viewer) {139$specs = array(140'phabricator',141'arcanist',142);143144$all_libraries = PhutilBootloader::getInstance()->getAllLibraries();145// This puts the core libraries at the top:146$other_libraries = array_diff($all_libraries, $specs);147$specs = array_merge($specs, $other_libraries);148149$log_futures = array();150$remote_futures = array();151152foreach ($specs as $lib) {153$root = dirname(phutil_get_library_root($lib));154155$log_command = csprintf(156'git log --format=%s -n 1 --',157'%H %ct');158159$remote_command = csprintf(160'git remote -v');161162$log_futures[$lib] = id(new ExecFuture('%C', $log_command))163->setCWD($root);164165$remote_futures[$lib] = id(new ExecFuture('%C', $remote_command))166->setCWD($root);167}168169$all_futures = array_merge($log_futures, $remote_futures);170171id(new FutureIterator($all_futures))172->resolveAll();173174// A repository may have a bunch of remotes, but we're only going to look175// for remotes we host to try to figure out where this repository branched.176$upstream_pattern = '(github\.com/phacility/|secure\.phabricator\.com/)';177178$upstream_futures = array();179$lib_upstreams = array();180foreach ($specs as $lib) {181$remote_future = $remote_futures[$lib];182183list($err, $stdout) = $remote_future->resolve();184if ($err) {185// If this fails for whatever reason, just move on.186continue;187}188189// These look like this, with a tab separating the first two fields:190// remote-name http://remote.uri/ (push)191192$upstreams = array();193194$remotes = phutil_split_lines($stdout, false);195foreach ($remotes as $remote) {196$remote_pattern = '/^([^\t]+)\t([^ ]+) \(([^)]+)\)\z/';197$matches = null;198if (!preg_match($remote_pattern, $remote, $matches)) {199continue;200}201202// Remote URIs are either "push" or "fetch": we only care about "fetch"203// URIs.204$type = $matches[3];205if ($type != 'fetch') {206continue;207}208209$uri = $matches[2];210$is_upstream = preg_match($upstream_pattern, $uri);211if (!$is_upstream) {212continue;213}214215$name = $matches[1];216$upstreams[$name] = $name;217}218219// If we have several suitable upstreams, try to pick the one named220// "origin", if it exists. Otherwise, just pick the first one.221if (isset($upstreams['origin'])) {222$upstream = $upstreams['origin'];223} else if ($upstreams) {224$upstream = head($upstreams);225} else {226$upstream = null;227}228229if (!$upstream) {230continue;231}232233$lib_upstreams[$lib] = $upstream;234235$merge_base_command = csprintf(236'git merge-base HEAD %s/master --',237$upstream);238239$root = dirname(phutil_get_library_root($lib));240241$upstream_futures[$lib] = id(new ExecFuture('%C', $merge_base_command))242->setCWD($root);243}244245if ($upstream_futures) {246id(new FutureIterator($upstream_futures))247->resolveAll();248}249250$results = array();251foreach ($log_futures as $lib => $future) {252list($err, $stdout) = $future->resolve();253if (!$err) {254list($hash, $epoch) = explode(' ', $stdout);255} else {256$hash = null;257$epoch = null;258}259260$result = array(261'hash' => $hash,262'epoch' => $epoch,263'upstream' => null,264'branchpoint' => null,265);266267$upstream_future = idx($upstream_futures, $lib);268if ($upstream_future) {269list($err, $stdout) = $upstream_future->resolve();270if (!$err) {271$branchpoint = trim($stdout);272if (strlen($branchpoint)) {273// We only list a branchpoint if it differs from HEAD.274if ($branchpoint != $hash) {275$result['upstream'] = $lib_upstreams[$lib];276$result['branchpoint'] = trim($stdout);277}278}279}280}281282$results[$lib] = $result;283}284285return $results;286}287288private function newBinaryVersionTable() {289$rows = array();290291$rows[] = array(292'php',293phpversion(),294php_sapi_name(),295);296297$binaries = PhutilBinaryAnalyzer::getAllBinaries();298foreach ($binaries as $binary) {299if (!$binary->isBinaryAvailable()) {300$binary_version = pht('Not Available');301$binary_path = null;302} else {303$binary_version = $binary->getBinaryVersion();304$binary_path = $binary->getBinaryPath();305}306307$rows[] = array(308$binary->getBinaryName(),309$binary_version,310$binary_path,311);312}313314$table_view = id(new AphrontTableView($rows))315->setHeaders(316array(317pht('Binary'),318pht('Version'),319pht('Path'),320))321->setColumnClasses(322array(323'pri',324null,325'wide',326));327328return id(new PHUIObjectBoxView())329->setHeaderText(pht('Other Version Information'))330->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)331->appendChild($table_view);332}333334335}336337338