3 final class PhabricatorConfigConsoleController
4 extends PhabricatorConfigController
{
6 public function handleRequest(AphrontRequest
$request) {
7 $viewer = $request->getViewer();
9 $menu = id(new PHUIObjectItemListView())
14 id(new PHUIObjectItemView())
15 ->setHeader(pht('Settings'))
16 ->setHref($this->getApplicationURI('settings/'))
17 ->setImageIcon('fa-wrench')
21 'Review and modify configuration settings.')));
24 id(new PHUIObjectItemView())
25 ->setHeader(pht('Setup Issues'))
26 ->setHref($this->getApplicationURI('issue/'))
27 ->setImageIcon('fa-exclamation-triangle')
31 'Show unresolved issues with setup and configuration.')));
34 id(new PHUIObjectItemView())
35 ->setHeader(pht('Services'))
36 ->setHref($this->getApplicationURI('cluster/databases/'))
37 ->setImageIcon('fa-server')
41 'View status information for databases, caches, repositories, '.
42 'and other services.')));
45 id(new PHUIObjectItemView())
46 ->setHeader(pht('Extensions/Modules'))
47 ->setHref($this->getApplicationURI('module/'))
48 ->setImageIcon('fa-gear')
52 'Show installed extensions and modules.')));
54 $crumbs = $this->buildApplicationCrumbs()
55 ->addTextCrumb(pht('Console'))
58 $box = id(new PHUIObjectBoxView())
59 ->setHeaderText(pht('Configuration'))
60 ->setBackground(PHUIObjectBoxView
::WHITE_CONFIG
)
61 ->setObjectList($menu);
63 $versions = $this->newLibraryVersionTable($viewer);
64 $binary_versions = $this->newBinaryVersionTable();
66 $launcher_view = id(new PHUILauncherView())
68 ->appendChild($versions)
69 ->appendChild($binary_versions);
71 $view = id(new PHUITwoColumnView())
72 ->setFooter($launcher_view);
74 return $this->newPage()
75 ->setTitle(pht('Configuration'))
80 public function newLibraryVersionTable() {
81 $viewer = $this->getViewer();
83 $versions = $this->loadVersions($viewer);
86 foreach ($versions as $name => $info) {
87 $branchpoint = $info['branchpoint'];
88 if (strlen($branchpoint)) {
89 $branchpoint = substr($branchpoint, 0, 12);
94 $version = $info['hash'];
95 if (strlen($version)) {
96 $version = substr($version, 0, 12);
98 $version = pht('Unknown');
102 $epoch = $info['epoch'];
104 $epoch = phabricator_date($epoch, $viewer);
117 $table_view = id(new AphrontTableView($rows))
133 return id(new PHUIObjectBoxView())
134 ->setHeaderText(pht('Version Information'))
135 ->setBackground(PHUIObjectBoxView
::BLUE_PROPERTY
)
136 ->appendChild($table_view);
139 private function loadVersions(PhabricatorUser
$viewer) {
145 $all_libraries = PhutilBootloader
::getInstance()->getAllLibraries();
146 // This puts the core libraries at the top:
147 $other_libraries = array_diff($all_libraries, $specs);
148 $specs = array_merge($specs, $other_libraries);
150 $log_futures = array();
151 $remote_futures = array();
153 foreach ($specs as $lib) {
154 $root = dirname(phutil_get_library_root($lib));
156 $log_command = csprintf(
157 'git log --format=%s -n 1 --',
160 $remote_command = csprintf(
163 $log_futures[$lib] = id(new ExecFuture('%C', $log_command))
166 $remote_futures[$lib] = id(new ExecFuture('%C', $remote_command))
170 $all_futures = array_merge($log_futures, $remote_futures);
172 id(new FutureIterator($all_futures))
175 // A repository may have a bunch of remotes, but we're only going to look
176 // for remotes we host to try to figure out where this repository branched.
177 $upstream_pattern = '(github\.com/phacility/|secure\.phabricator\.com/)';
179 $upstream_futures = array();
180 $lib_upstreams = array();
181 foreach ($specs as $lib) {
182 $remote_future = $remote_futures[$lib];
184 list($err, $stdout) = $remote_future->resolve();
186 // If this fails for whatever reason, just move on.
190 // These look like this, with a tab separating the first two fields:
191 // remote-name http://remote.uri/ (push)
193 $upstreams = array();
195 $remotes = phutil_split_lines($stdout, false);
196 foreach ($remotes as $remote) {
197 $remote_pattern = '/^([^\t]+)\t([^ ]+) \(([^)]+)\)\z/';
199 if (!preg_match($remote_pattern, $remote, $matches)) {
203 // Remote URIs are either "push" or "fetch": we only care about "fetch"
206 if ($type != 'fetch') {
211 $is_upstream = preg_match($upstream_pattern, $uri);
217 $upstreams[$name] = $name;
220 // If we have several suitable upstreams, try to pick the one named
221 // "origin", if it exists. Otherwise, just pick the first one.
222 if (isset($upstreams['origin'])) {
223 $upstream = $upstreams['origin'];
224 } else if ($upstreams) {
225 $upstream = head($upstreams);
234 $lib_upstreams[$lib] = $upstream;
236 $merge_base_command = csprintf(
237 'git merge-base HEAD %s/master --',
240 $root = dirname(phutil_get_library_root($lib));
242 $upstream_futures[$lib] = id(new ExecFuture('%C', $merge_base_command))
246 if ($upstream_futures) {
247 id(new FutureIterator($upstream_futures))
252 foreach ($log_futures as $lib => $future) {
253 list($err, $stdout) = $future->resolve();
255 list($hash, $epoch) = explode(' ', $stdout);
265 'branchpoint' => null,
268 $upstream_future = idx($upstream_futures, $lib);
269 if ($upstream_future) {
270 list($err, $stdout) = $upstream_future->resolve();
272 $branchpoint = trim($stdout);
273 if (strlen($branchpoint)) {
274 // We only list a branchpoint if it differs from HEAD.
275 if ($branchpoint != $hash) {
276 $result['upstream'] = $lib_upstreams[$lib];
277 $result['branchpoint'] = trim($stdout);
283 $results[$lib] = $result;
289 private function newBinaryVersionTable() {
298 $binaries = PhutilBinaryAnalyzer
::getAllBinaries();
299 foreach ($binaries as $binary) {
300 if (!$binary->isBinaryAvailable()) {
301 $binary_version = pht('Not Available');
304 $binary_version = $binary->getBinaryVersion();
305 $binary_path = $binary->getBinaryPath();
309 $binary->getBinaryName(),
315 $table_view = id(new AphrontTableView($rows))
329 return id(new PHUIObjectBoxView())
330 ->setHeaderText(pht('Other Version Information'))
331 ->setBackground(PHUIObjectBoxView
::BLUE_PROPERTY
)
332 ->appendChild($table_view);