mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-19 12:00:55 +01:00
Merge branch 'master' of github.com:facebook/phabricator into unit_status
This commit is contained in:
commit
7f601a78d3
46 changed files with 1006 additions and 182 deletions
20
resources/sql/patches/072.blamerevert.sql
Normal file
20
resources/sql/patches/072.blamerevert.sql
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
INSERT INTO phabricator_differential.differential_auxiliaryfield
|
||||||
|
(revisionPHID, name, value, dateCreated, dateModified)
|
||||||
|
SELECT phid, 'phabricator:blame-revision', blameRevision,
|
||||||
|
dateCreated, dateModified
|
||||||
|
FROM phabricator_differential.differential_revision
|
||||||
|
WHERE blameRevision != '';
|
||||||
|
|
||||||
|
ALTER TABLE phabricator_differential.differential_revision
|
||||||
|
DROP blameRevision;
|
||||||
|
|
||||||
|
|
||||||
|
INSERT INTO phabricator_differential.differential_auxiliaryfield
|
||||||
|
(revisionPHID, name, value, dateCreated, dateModified)
|
||||||
|
SELECT phid, 'phabricator:revert-plan', revertPlan,
|
||||||
|
dateCreated, dateModified
|
||||||
|
FROM phabricator_differential.differential_revision
|
||||||
|
WHERE revertPlan != '';
|
||||||
|
|
||||||
|
ALTER TABLE phabricator_differential.differential_revision
|
||||||
|
DROP revertPlan;
|
90
scripts/repository/test_connection.php
Executable file
90
scripts/repository/test_connection.php
Executable file
|
@ -0,0 +1,90 @@
|
||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2011 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
$root = dirname(dirname(dirname(__FILE__)));
|
||||||
|
require_once $root.'/scripts/__init_script__.php';
|
||||||
|
require_once $root.'/scripts/__init_env__.php';
|
||||||
|
|
||||||
|
phutil_require_module('phutil', 'console');
|
||||||
|
phutil_require_module('phutil', 'future/exec');
|
||||||
|
|
||||||
|
if (empty($argv[1])) {
|
||||||
|
echo "usage: test_connection.php <repository_callsign>\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
echo phutil_console_wrap(
|
||||||
|
phutil_console_format(
|
||||||
|
'This script will test that you have configured valid credentials for '.
|
||||||
|
'access to a repository, so the Phabricator daemons can pull from it. '.
|
||||||
|
'You should run this as the **same user you will run the daemons as**, '.
|
||||||
|
'from the **same machine they will run from**. Doing this will help '.
|
||||||
|
'detect various problems with your configuration, such as SSH issues.'));
|
||||||
|
|
||||||
|
list($whoami) = execx('whoami');
|
||||||
|
$whoami = trim($whoami);
|
||||||
|
|
||||||
|
$ok = phutil_console_confirm("Do you want to continue as '{$whoami}'?");
|
||||||
|
if (!$ok) {
|
||||||
|
die(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
$callsign = $argv[1];
|
||||||
|
echo "Loading '{$callsign}' repository...\n";
|
||||||
|
$repository = id(new PhabricatorRepository())->loadOneWhere(
|
||||||
|
'callsign = %s',
|
||||||
|
$argv[1]);
|
||||||
|
if (!$repository) {
|
||||||
|
throw new Exception("No such repository exists!");
|
||||||
|
}
|
||||||
|
|
||||||
|
$vcs = $repository->getVersionControlSystem();
|
||||||
|
|
||||||
|
PhutilServiceProfiler::installEchoListener();
|
||||||
|
|
||||||
|
echo "Trying to connect to the remote...\n";
|
||||||
|
switch ($vcs) {
|
||||||
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
|
||||||
|
$err = $repository->passthruRemoteCommand(
|
||||||
|
'--limit 1 log %s',
|
||||||
|
$repository->getRemoteURI());
|
||||||
|
break;
|
||||||
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
|
||||||
|
// Do an ls-remote on a nonexistent ref, which we expect to just return
|
||||||
|
// nothing.
|
||||||
|
$err = $repository->passthruRemoteCommand(
|
||||||
|
'ls-remote %s %s',
|
||||||
|
$repository->getRemoteURI(),
|
||||||
|
'just-testing');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception("Unsupported repository type.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($err) {
|
||||||
|
echo phutil_console_format(
|
||||||
|
"<bg:red>** FAIL **</bg> Connection failed. The credentials for this ".
|
||||||
|
"repository appear to be incorrectly configured.\n");
|
||||||
|
exit(1);
|
||||||
|
} else {
|
||||||
|
echo phutil_console_format(
|
||||||
|
"<bg:green>** OKAY **</bg> Connection successful. The credentials for ".
|
||||||
|
"this repository appear to be correctly configured.\n");
|
||||||
|
}
|
||||||
|
|
|
@ -172,7 +172,7 @@ celerity_register_resource_map(array(
|
||||||
),
|
),
|
||||||
'differential-core-view-css' =>
|
'differential-core-view-css' =>
|
||||||
array(
|
array(
|
||||||
'uri' => '/res/438fe316/rsrc/css/application/differential/core.css',
|
'uri' => '/res/584d40e8/rsrc/css/application/differential/core.css',
|
||||||
'type' => 'css',
|
'type' => 'css',
|
||||||
'requires' =>
|
'requires' =>
|
||||||
array(
|
array(
|
||||||
|
@ -1180,7 +1180,7 @@ celerity_register_resource_map(array(
|
||||||
),
|
),
|
||||||
'phabricator-content-source-view-css' =>
|
'phabricator-content-source-view-css' =>
|
||||||
array(
|
array(
|
||||||
'uri' => '/res/7147f14c/rsrc/css/application/contentsource/content-source-view.css',
|
'uri' => '/res/8c738a93/rsrc/css/application/contentsource/content-source-view.css',
|
||||||
'type' => 'css',
|
'type' => 'css',
|
||||||
'requires' =>
|
'requires' =>
|
||||||
array(
|
array(
|
||||||
|
@ -1419,7 +1419,7 @@ celerity_register_resource_map(array(
|
||||||
'uri' => '/res/pkg/3dbf4083/javelin.pkg.js',
|
'uri' => '/res/pkg/3dbf4083/javelin.pkg.js',
|
||||||
'type' => 'js',
|
'type' => 'js',
|
||||||
),
|
),
|
||||||
'3f2092d7' =>
|
'7bf96a66' =>
|
||||||
array(
|
array(
|
||||||
'name' => 'differential.pkg.css',
|
'name' => 'differential.pkg.css',
|
||||||
'symbols' =>
|
'symbols' =>
|
||||||
|
@ -1433,7 +1433,7 @@ celerity_register_resource_map(array(
|
||||||
6 => 'differential-revision-add-comment-css',
|
6 => 'differential-revision-add-comment-css',
|
||||||
7 => 'differential-revision-comment-list-css',
|
7 => 'differential-revision-comment-list-css',
|
||||||
),
|
),
|
||||||
'uri' => '/res/pkg/3f2092d7/differential.pkg.css',
|
'uri' => '/res/pkg/7bf96a66/differential.pkg.css',
|
||||||
'type' => 'css',
|
'type' => 'css',
|
||||||
),
|
),
|
||||||
'95c67dcd' =>
|
'95c67dcd' =>
|
||||||
|
@ -1518,14 +1518,14 @@ celerity_register_resource_map(array(
|
||||||
'aphront-table-view-css' => '70966590',
|
'aphront-table-view-css' => '70966590',
|
||||||
'aphront-tokenizer-control-css' => '70966590',
|
'aphront-tokenizer-control-css' => '70966590',
|
||||||
'aphront-typeahead-control-css' => '70966590',
|
'aphront-typeahead-control-css' => '70966590',
|
||||||
'differential-changeset-view-css' => '3f2092d7',
|
'differential-changeset-view-css' => '7bf96a66',
|
||||||
'differential-core-view-css' => '3f2092d7',
|
'differential-core-view-css' => '7bf96a66',
|
||||||
'differential-revision-add-comment-css' => '3f2092d7',
|
'differential-revision-add-comment-css' => '7bf96a66',
|
||||||
'differential-revision-comment-css' => '3f2092d7',
|
'differential-revision-comment-css' => '7bf96a66',
|
||||||
'differential-revision-comment-list-css' => '3f2092d7',
|
'differential-revision-comment-list-css' => '7bf96a66',
|
||||||
'differential-revision-detail-css' => '3f2092d7',
|
'differential-revision-detail-css' => '7bf96a66',
|
||||||
'differential-revision-history-css' => '3f2092d7',
|
'differential-revision-history-css' => '7bf96a66',
|
||||||
'differential-table-of-contents-css' => '3f2092d7',
|
'differential-table-of-contents-css' => '7bf96a66',
|
||||||
'diffusion-commit-view-css' => '03ef179e',
|
'diffusion-commit-view-css' => '03ef179e',
|
||||||
'javelin-behavior' => '3dbf4083',
|
'javelin-behavior' => '3dbf4083',
|
||||||
'javelin-behavior-aphront-basic-tokenizer' => 'ac869011',
|
'javelin-behavior-aphront-basic-tokenizer' => 'ac869011',
|
||||||
|
|
|
@ -642,6 +642,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorUserLog' => 'applications/people/storage/log',
|
'PhabricatorUserLog' => 'applications/people/storage/log',
|
||||||
'PhabricatorUserOAuthInfo' => 'applications/people/storage/useroauthinfo',
|
'PhabricatorUserOAuthInfo' => 'applications/people/storage/useroauthinfo',
|
||||||
'PhabricatorUserOAuthSettingsPanelController' => 'applications/people/controller/settings/panels/oauth',
|
'PhabricatorUserOAuthSettingsPanelController' => 'applications/people/controller/settings/panels/oauth',
|
||||||
|
'PhabricatorUserPasswordSettingsPanelController' => 'applications/people/controller/settings/panels/password',
|
||||||
'PhabricatorUserPreferenceSettingsPanelController' => 'applications/people/controller/settings/panels/preferences',
|
'PhabricatorUserPreferenceSettingsPanelController' => 'applications/people/controller/settings/panels/preferences',
|
||||||
'PhabricatorUserPreferences' => 'applications/people/storage/preferences',
|
'PhabricatorUserPreferences' => 'applications/people/storage/preferences',
|
||||||
'PhabricatorUserProfile' => 'applications/people/storage/profile',
|
'PhabricatorUserProfile' => 'applications/people/storage/profile',
|
||||||
|
@ -1222,6 +1223,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorUserLog' => 'PhabricatorUserDAO',
|
'PhabricatorUserLog' => 'PhabricatorUserDAO',
|
||||||
'PhabricatorUserOAuthInfo' => 'PhabricatorUserDAO',
|
'PhabricatorUserOAuthInfo' => 'PhabricatorUserDAO',
|
||||||
'PhabricatorUserOAuthSettingsPanelController' => 'PhabricatorUserSettingsPanelController',
|
'PhabricatorUserOAuthSettingsPanelController' => 'PhabricatorUserSettingsPanelController',
|
||||||
|
'PhabricatorUserPasswordSettingsPanelController' => 'PhabricatorUserSettingsPanelController',
|
||||||
'PhabricatorUserPreferenceSettingsPanelController' => 'PhabricatorUserSettingsPanelController',
|
'PhabricatorUserPreferenceSettingsPanelController' => 'PhabricatorUserSettingsPanelController',
|
||||||
'PhabricatorUserPreferences' => 'PhabricatorUserDAO',
|
'PhabricatorUserPreferences' => 'PhabricatorUserDAO',
|
||||||
'PhabricatorUserProfile' => 'PhabricatorUserDAO',
|
'PhabricatorUserProfile' => 'PhabricatorUserDAO',
|
||||||
|
|
|
@ -145,6 +145,22 @@ class AphrontRequest {
|
||||||
|
|
||||||
$valid = $this->getUser()->validateCSRFToken($token);
|
$valid = $this->getUser()->validateCSRFToken($token);
|
||||||
if (!$valid) {
|
if (!$valid) {
|
||||||
|
|
||||||
|
// Add some diagnostic details so we can figure out if some CSRF issues
|
||||||
|
// are JS problems or people accessing Ajax URIs directly with their
|
||||||
|
// browsers.
|
||||||
|
if ($token) {
|
||||||
|
$token_info = "with an invalid CSRF token";
|
||||||
|
} else {
|
||||||
|
$token_info = "without a CSRF token";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->isAjax()) {
|
||||||
|
$more_info = "(This was an Ajax request, {$token_info}.)";
|
||||||
|
} else {
|
||||||
|
$more_info = "(This was a web request, {$token_info}.)";
|
||||||
|
}
|
||||||
|
|
||||||
// This should only be able to happen if you load a form, pull your
|
// This should only be able to happen if you load a form, pull your
|
||||||
// internet for 6 hours, and then reconnect and immediately submit,
|
// internet for 6 hours, and then reconnect and immediately submit,
|
||||||
// but give the user some indication of what happened since the workflow
|
// but give the user some indication of what happened since the workflow
|
||||||
|
@ -155,7 +171,8 @@ class AphrontRequest {
|
||||||
"certain type of login hijacking attack. However, the token can ".
|
"certain type of login hijacking attack. However, the token can ".
|
||||||
"become invalid if you leave a page open for more than six hours ".
|
"become invalid if you leave a page open for more than six hours ".
|
||||||
"without a connection to the internet. To fix this problem: reload ".
|
"without a connection to the internet. To fix this problem: reload ".
|
||||||
"the page, and then resubmit it.");
|
"the page, and then resubmit it.\n\n".
|
||||||
|
$more_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -39,7 +39,15 @@ class PhabricatorLogoutController extends PhabricatorAuthController {
|
||||||
PhabricatorUserLog::ACTION_LOGOUT);
|
PhabricatorUserLog::ACTION_LOGOUT);
|
||||||
$log->save();
|
$log->save();
|
||||||
|
|
||||||
|
// Destroy the user's session in the database so logout works even if
|
||||||
|
// their cookies have some issues. We'll detect cookie issues when they
|
||||||
|
// try to login again and tell them to clear any junk.
|
||||||
|
$phsid = $request->getCookie('phsid');
|
||||||
|
if ($phsid) {
|
||||||
|
$user->destroySession($phsid);
|
||||||
|
}
|
||||||
$request->clearCookie('phsid');
|
$request->clearCookie('phsid');
|
||||||
|
|
||||||
return id(new AphrontRedirectResponse())
|
return id(new AphrontRedirectResponse())
|
||||||
->setURI('/login/');
|
->setURI('/login/');
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,8 +91,6 @@ class ConduitAPI_differential_getrevision_Method extends ConduitAPIMethod {
|
||||||
$revision->getStatus()),
|
$revision->getStatus()),
|
||||||
'summary' => $revision->getSummary(),
|
'summary' => $revision->getSummary(),
|
||||||
'testPlan' => $revision->getTestPlan(),
|
'testPlan' => $revision->getTestPlan(),
|
||||||
'revertPlan' => $revision->getRevertPlan(),
|
|
||||||
'blameRevision' => $revision->getBlameRevision(),
|
|
||||||
'lineCount' => $revision->getLineCount(),
|
'lineCount' => $revision->getLineCount(),
|
||||||
'reviewerPHIDs' => $reviewer_phids,
|
'reviewerPHIDs' => $reviewer_phids,
|
||||||
'diffs' => $diff_dicts,
|
'diffs' => $diff_dicts,
|
||||||
|
|
|
@ -46,6 +46,35 @@ class PhabricatorWorkerTaskDetailController
|
||||||
$data = id(new PhabricatorWorkerTaskData())->loadOneWhere(
|
$data = id(new PhabricatorWorkerTaskData())->loadOneWhere(
|
||||||
'id = %d',
|
'id = %d',
|
||||||
$task->getDataID());
|
$task->getDataID());
|
||||||
|
|
||||||
|
$extra = null;
|
||||||
|
switch ($task->getTaskClass()) {
|
||||||
|
case 'PhabricatorRepositorySvnCommitChangeParserWorker':
|
||||||
|
case 'PhabricatorRepositoryGitCommitChangeParserWorker':
|
||||||
|
$commit_id = idx($data->getData(), 'commitID');
|
||||||
|
if ($commit_id) {
|
||||||
|
$commit = id(new PhabricatorRepositoryCommit())->load($commit_id);
|
||||||
|
if ($commit) {
|
||||||
|
$repository = id(new PhabricatorRepository())->load(
|
||||||
|
$commit->getRepositoryID());
|
||||||
|
if ($repository) {
|
||||||
|
$extra =
|
||||||
|
"<strong>NOTE:</strong> ".
|
||||||
|
"You can manually retry this task by running this script:".
|
||||||
|
"<pre>".
|
||||||
|
"phabricator/\$ ./scripts/repository/parse_one_commit.php ".
|
||||||
|
"r".
|
||||||
|
phutil_escape_html($repository->getCallsign()).
|
||||||
|
phutil_escape_html($commit->getCommitIdentifier()).
|
||||||
|
"</pre>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if ($data) {
|
if ($data) {
|
||||||
$data = json_encode($data->getData());
|
$data = json_encode($data->getData());
|
||||||
}
|
}
|
||||||
|
@ -75,14 +104,23 @@ class PhabricatorWorkerTaskDetailController
|
||||||
->appendChild(
|
->appendChild(
|
||||||
id(new AphrontFormTextAreaControl())
|
id(new AphrontFormTextAreaControl())
|
||||||
->setLabel('Data')
|
->setLabel('Data')
|
||||||
->setValue($data))
|
->setValue($data));
|
||||||
|
|
||||||
|
if ($extra) {
|
||||||
|
$form->appendChild(
|
||||||
|
id(new AphrontFormMarkupControl())
|
||||||
|
->setLabel('More')
|
||||||
|
->setValue($extra));
|
||||||
|
}
|
||||||
|
|
||||||
|
$form
|
||||||
->appendChild(
|
->appendChild(
|
||||||
id(new AphrontFormSubmitControl())
|
id(new AphrontFormSubmitControl())
|
||||||
->addCancelButton('/daemon/'));
|
->addCancelButton('/daemon/'));
|
||||||
|
|
||||||
$panel = new AphrontPanelView();
|
$panel = new AphrontPanelView();
|
||||||
$panel->setHeader('Task Detail');
|
$panel->setHeader('Task Detail');
|
||||||
$panel->setWidth(AphrontPanelView::WIDTH_FORM);
|
$panel->setWidth(AphrontPanelView::WIDTH_WIDE);
|
||||||
$panel->appendChild($form);
|
$panel->appendChild($form);
|
||||||
|
|
||||||
return $this->buildStandardPageResponse(
|
return $this->buildStandardPageResponse(
|
||||||
|
|
|
@ -7,15 +7,19 @@
|
||||||
|
|
||||||
|
|
||||||
phutil_require_module('phabricator', 'applications/daemon/controller/base');
|
phutil_require_module('phabricator', 'applications/daemon/controller/base');
|
||||||
|
phutil_require_module('phabricator', 'applications/repository/storage/commit');
|
||||||
|
phutil_require_module('phabricator', 'applications/repository/storage/repository');
|
||||||
phutil_require_module('phabricator', 'infrastructure/daemon/workers/storage/task');
|
phutil_require_module('phabricator', 'infrastructure/daemon/workers/storage/task');
|
||||||
phutil_require_module('phabricator', 'infrastructure/daemon/workers/storage/taskdata');
|
phutil_require_module('phabricator', 'infrastructure/daemon/workers/storage/taskdata');
|
||||||
phutil_require_module('phabricator', 'view/form/base');
|
phutil_require_module('phabricator', 'view/form/base');
|
||||||
|
phutil_require_module('phabricator', 'view/form/control/markup');
|
||||||
phutil_require_module('phabricator', 'view/form/control/static');
|
phutil_require_module('phabricator', 'view/form/control/static');
|
||||||
phutil_require_module('phabricator', 'view/form/control/submit');
|
phutil_require_module('phabricator', 'view/form/control/submit');
|
||||||
phutil_require_module('phabricator', 'view/form/control/textarea');
|
phutil_require_module('phabricator', 'view/form/control/textarea');
|
||||||
phutil_require_module('phabricator', 'view/form/error');
|
phutil_require_module('phabricator', 'view/form/error');
|
||||||
phutil_require_module('phabricator', 'view/layout/panel');
|
phutil_require_module('phabricator', 'view/layout/panel');
|
||||||
|
|
||||||
|
phutil_require_module('phutil', 'markup');
|
||||||
phutil_require_module('phutil', 'utils');
|
phutil_require_module('phutil', 'utils');
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -175,12 +175,6 @@ class DifferentialRevisionEditor {
|
||||||
if ($revision->getAuthorPHID() === null) {
|
if ($revision->getAuthorPHID() === null) {
|
||||||
$revision->setAuthorPHID($this->getActorPHID());
|
$revision->setAuthorPHID($this->getActorPHID());
|
||||||
}
|
}
|
||||||
if ($revision->getRevertPlan() === null) {
|
|
||||||
$revision->setRevertPlan('');
|
|
||||||
}
|
|
||||||
if ($revision->getBlameRevision() === null) {
|
|
||||||
$revision->setBlameRevision('');
|
|
||||||
}
|
|
||||||
if ($revision->getSummary() === null) {
|
if ($revision->getSummary() === null) {
|
||||||
$revision->setSummary('');
|
$revision->setSummary('');
|
||||||
}
|
}
|
||||||
|
|
|
@ -899,22 +899,66 @@ class DifferentialChangesetParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->comments = msort($this->comments, 'getID');
|
||||||
|
$old_comments = array();
|
||||||
|
$new_comments = array();
|
||||||
|
foreach ($this->comments as $comment) {
|
||||||
|
if ($this->isCommentOnRightSideWhenDisplayed($comment)) {
|
||||||
|
$new_comments[] = $comment;
|
||||||
|
} else {
|
||||||
|
$old_comments[] = $comment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$html_old = array();
|
||||||
|
$html_new = array();
|
||||||
|
foreach ($old_comments as $comment) {
|
||||||
|
$xhp = $this->renderInlineComment($comment);
|
||||||
|
$html_old[] =
|
||||||
|
'<tr class="inline"><th /><td>'.
|
||||||
|
$xhp.
|
||||||
|
'</td><th /><td /></tr>';
|
||||||
|
}
|
||||||
|
foreach ($new_comments as $comment) {
|
||||||
|
$xhp = $this->renderInlineComment($comment);
|
||||||
|
$html_new[] =
|
||||||
|
'<tr class="inline"><th /><td /><th /><td>'.
|
||||||
|
$xhp.
|
||||||
|
'</td></tr>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$changset_id = $this->changeset->getID();
|
||||||
|
if (!$old) {
|
||||||
|
$th_old = '<th></th>';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$th_old = '<th id="C'.$changset_id.'OL1">1</th>';
|
||||||
|
}
|
||||||
|
if (!$cur) {
|
||||||
|
$th_new = '<th></th>';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$th_new = '<th id="C'.$changset_id.'NL1">1</th>';
|
||||||
|
}
|
||||||
|
|
||||||
$output = $this->renderChangesetTable(
|
$output = $this->renderChangesetTable(
|
||||||
$this->changeset,
|
$this->changeset,
|
||||||
'<tr>'.
|
'<tr>'.
|
||||||
'<th></th>'.
|
$th_old.
|
||||||
'<td class="differential-old-image">'.
|
'<td class="differential-old-image">'.
|
||||||
'<div class="differential-image-stage">'.
|
'<div class="differential-image-stage">'.
|
||||||
$old.
|
$old.
|
||||||
'</div>'.
|
'</div>'.
|
||||||
'</td>'.
|
'</td>'.
|
||||||
'<th></th>'.
|
$th_new.
|
||||||
'<td class="differential-new-image">'.
|
'<td class="differential-new-image">'.
|
||||||
'<div class="differential-image-stage">'.
|
'<div class="differential-image-stage">'.
|
||||||
$cur.
|
$cur.
|
||||||
'</div>'.
|
'</div>'.
|
||||||
'</td>'.
|
'</td>'.
|
||||||
'</tr>');
|
'</tr>'.
|
||||||
|
implode('', $html_old).
|
||||||
|
implode('', $html_new));
|
||||||
|
|
||||||
return $output;
|
return $output;
|
||||||
case DifferentialChangeType::FILE_DIRECTORY:
|
case DifferentialChangeType::FILE_DIRECTORY:
|
||||||
|
|
|
@ -23,8 +23,6 @@ class DifferentialRevision extends DifferentialDAO {
|
||||||
|
|
||||||
protected $summary;
|
protected $summary;
|
||||||
protected $testPlan;
|
protected $testPlan;
|
||||||
protected $revertPlan;
|
|
||||||
protected $blameRevision;
|
|
||||||
|
|
||||||
protected $phid;
|
protected $phid;
|
||||||
protected $authorPHID;
|
protected $authorPHID;
|
||||||
|
|
|
@ -75,6 +75,16 @@ class DiffusionBrowseController extends DiffusionController {
|
||||||
$controller->setDiffusionRequest($drequest);
|
$controller->setDiffusionRequest($drequest);
|
||||||
return $this->delegateToController($controller);
|
return $this->delegateToController($controller);
|
||||||
break;
|
break;
|
||||||
|
case DiffusionBrowseQuery::REASON_IS_UNTRACKED_PARENT:
|
||||||
|
$subdir = $drequest->getRepository()->getDetail('svn-subpath');
|
||||||
|
$title = 'Directory Not Tracked';
|
||||||
|
$body =
|
||||||
|
"This repository is configured to track only one subdirectory ".
|
||||||
|
"of the entire repository ('".phutil_escape_html($subdir)."'), ".
|
||||||
|
"but you aren't looking at something in that subdirectory, so no ".
|
||||||
|
"information is available.";
|
||||||
|
$severity = AphrontErrorView::SEVERITY_WARNING;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Exception("Unknown failure reason!");
|
throw new Exception("Unknown failure reason!");
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ phutil_require_module('phabricator', 'applications/phid/handle/data');
|
||||||
phutil_require_module('phabricator', 'view/form/error');
|
phutil_require_module('phabricator', 'view/form/error');
|
||||||
phutil_require_module('phabricator', 'view/layout/panel');
|
phutil_require_module('phabricator', 'view/layout/panel');
|
||||||
|
|
||||||
|
phutil_require_module('phutil', 'markup');
|
||||||
phutil_require_module('phutil', 'utils');
|
phutil_require_module('phutil', 'utils');
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -44,31 +44,47 @@ class DiffusionCommitController extends DiffusionController {
|
||||||
|
|
||||||
$commit_data = $drequest->loadCommitData();
|
$commit_data = $drequest->loadCommitData();
|
||||||
|
|
||||||
$engine = PhabricatorMarkupEngine::newDifferentialMarkupEngine();
|
$is_foreign = $commit_data->getCommitDetail('foreign-svn-stub');
|
||||||
|
if ($is_foreign) {
|
||||||
|
$subpath = $commit_data->getCommitDetail('svn-subpath');
|
||||||
|
|
||||||
require_celerity_resource('diffusion-commit-view-css');
|
$error_panel = new AphrontErrorView();
|
||||||
require_celerity_resource('phabricator-remarkup-css');
|
$error_panel->setWidth(AphrontErrorView::WIDTH_WIDE);
|
||||||
|
$error_panel->setTitle('Commit Not Tracked');
|
||||||
|
$error_panel->setSeverity(AphrontErrorView::SEVERITY_WARNING);
|
||||||
|
$error_panel->appendChild(
|
||||||
|
"This Diffusion repository is configured to track only one ".
|
||||||
|
"subdirectory of the entire Subversion repository, and this commit ".
|
||||||
|
"didn't affect the tracked subdirectory ('".
|
||||||
|
phutil_escape_html($subpath)."'), so no information is available.");
|
||||||
|
$content[] = $error_panel;
|
||||||
|
} else {
|
||||||
|
$engine = PhabricatorMarkupEngine::newDifferentialMarkupEngine();
|
||||||
|
|
||||||
$property_table = $this->renderPropertyTable($commit, $commit_data);
|
require_celerity_resource('diffusion-commit-view-css');
|
||||||
|
require_celerity_resource('phabricator-remarkup-css');
|
||||||
|
|
||||||
$detail_panel->appendChild(
|
$property_table = $this->renderPropertyTable($commit, $commit_data);
|
||||||
'<div class="diffusion-commit-view">'.
|
|
||||||
'<div class="diffusion-commit-dateline">'.
|
$detail_panel->appendChild(
|
||||||
'r'.$callsign.$commit->getCommitIdentifier().
|
'<div class="diffusion-commit-view">'.
|
||||||
' · '.
|
'<div class="diffusion-commit-dateline">'.
|
||||||
phabricator_datetime($commit->getEpoch(), $user).
|
'r'.$callsign.$commit->getCommitIdentifier().
|
||||||
'</div>'.
|
' · '.
|
||||||
'<h1>Revision Detail</h1>'.
|
phabricator_datetime($commit->getEpoch(), $user).
|
||||||
'<div class="diffusion-commit-details">'.
|
|
||||||
$property_table.
|
|
||||||
'<hr />'.
|
|
||||||
'<div class="diffusion-commit-message phabricator-remarkup">'.
|
|
||||||
$engine->markupText($commit_data->getCommitMessage()).
|
|
||||||
'</div>'.
|
'</div>'.
|
||||||
'</div>'.
|
'<h1>Revision Detail</h1>'.
|
||||||
'</div>');
|
'<div class="diffusion-commit-details">'.
|
||||||
|
$property_table.
|
||||||
|
'<hr />'.
|
||||||
|
'<div class="diffusion-commit-message phabricator-remarkup">'.
|
||||||
|
$engine->markupText($commit_data->getCommitMessage()).
|
||||||
|
'</div>'.
|
||||||
|
'</div>'.
|
||||||
|
'</div>');
|
||||||
|
|
||||||
$content[] = $detail_panel;
|
$content[] = $detail_panel;
|
||||||
|
}
|
||||||
|
|
||||||
$change_query = DiffusionPathChangeQuery::newFromDiffusionRequest(
|
$change_query = DiffusionPathChangeQuery::newFromDiffusionRequest(
|
||||||
$drequest);
|
$drequest);
|
||||||
|
@ -103,6 +119,23 @@ class DiffusionCommitController extends DiffusionController {
|
||||||
phutil_escape_html($bad_commit['description']));
|
phutil_escape_html($bad_commit['description']));
|
||||||
|
|
||||||
$content[] = $error_panel;
|
$content[] = $error_panel;
|
||||||
|
} else if ($is_foreign) {
|
||||||
|
// Don't render anything else.
|
||||||
|
} else if (!count($changes)) {
|
||||||
|
$no_changes = new AphrontErrorView();
|
||||||
|
$no_changes->setWidth(AphrontErrorView::WIDTH_WIDE);
|
||||||
|
$no_changes->setSeverity(AphrontErrorView::SEVERITY_WARNING);
|
||||||
|
$no_changes->setTitle('Not Yet Parsed');
|
||||||
|
// TODO: This can also happen with weird SVN changes that don't do
|
||||||
|
// anything (or only alter properties?), although the real no-changes case
|
||||||
|
// is extremely rare and might be impossible to produce organically. We
|
||||||
|
// should probably write some kind of "Nothing Happened!" change into the
|
||||||
|
// DB once we parse these changes so we can distinguish between
|
||||||
|
// "not parsed yet" and "no changes".
|
||||||
|
$no_changes->appendChild(
|
||||||
|
"This commit hasn't been fully parsed yet (or doesn't affect any ".
|
||||||
|
"paths).");
|
||||||
|
$content[] = $no_changes;
|
||||||
} else {
|
} else {
|
||||||
$change_panel = new AphrontPanelView();
|
$change_panel = new AphrontPanelView();
|
||||||
$change_panel->setHeader("Changes (".number_format($count).")");
|
$change_panel->setHeader("Changes (".number_format($count).")");
|
||||||
|
@ -130,60 +163,52 @@ class DiffusionCommitController extends DiffusionController {
|
||||||
|
|
||||||
$content[] = $change_panel;
|
$content[] = $change_panel;
|
||||||
|
|
||||||
if ($changes) {
|
$changesets = DiffusionPathChange::convertToDifferentialChangesets(
|
||||||
$changesets = DiffusionPathChange::convertToDifferentialChangesets(
|
$changes);
|
||||||
$changes);
|
|
||||||
|
|
||||||
$vcs = $repository->getVersionControlSystem();
|
$vcs = $repository->getVersionControlSystem();
|
||||||
switch ($vcs) {
|
switch ($vcs) {
|
||||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
|
||||||
$vcs_supports_directory_changes = true;
|
$vcs_supports_directory_changes = true;
|
||||||
break;
|
break;
|
||||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
|
||||||
$vcs_supports_directory_changes = false;
|
$vcs_supports_directory_changes = false;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Exception("Unknown VCS.");
|
throw new Exception("Unknown VCS.");
|
||||||
}
|
|
||||||
|
|
||||||
$references = array();
|
|
||||||
foreach ($changesets as $key => $changeset) {
|
|
||||||
$file_type = $changeset->getFileType();
|
|
||||||
if ($file_type == DifferentialChangeType::FILE_DIRECTORY) {
|
|
||||||
if (!$vcs_supports_directory_changes) {
|
|
||||||
unset($changesets[$key]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$branch = $drequest->getBranchURIComponent(
|
|
||||||
$drequest->getBranch());
|
|
||||||
$filename = $changeset->getFilename();
|
|
||||||
$commit = $drequest->getCommit();
|
|
||||||
$reference = "{$branch}{$filename};{$commit}";
|
|
||||||
$references[$key] = $reference;
|
|
||||||
}
|
|
||||||
|
|
||||||
$change_list = new DifferentialChangesetListView();
|
|
||||||
$change_list->setChangesets($changesets);
|
|
||||||
$change_list->setRenderingReferences($references);
|
|
||||||
$change_list->setRenderURI('/diffusion/'.$callsign.'/diff/');
|
|
||||||
|
|
||||||
// TODO: This is pretty awkward, unify the CSS between Diffusion and
|
|
||||||
// Differential better.
|
|
||||||
require_celerity_resource('differential-core-view-css');
|
|
||||||
$change_list =
|
|
||||||
'<div class="differential-primary-pane">'.
|
|
||||||
$change_list->render().
|
|
||||||
'</div>';
|
|
||||||
} else {
|
|
||||||
$change_list =
|
|
||||||
'<div style="margin: 2em; color: #666; padding: 1em;
|
|
||||||
background: #eee;">'.
|
|
||||||
'(no changes blah blah)'.
|
|
||||||
'</div>';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$references = array();
|
||||||
|
foreach ($changesets as $key => $changeset) {
|
||||||
|
$file_type = $changeset->getFileType();
|
||||||
|
if ($file_type == DifferentialChangeType::FILE_DIRECTORY) {
|
||||||
|
if (!$vcs_supports_directory_changes) {
|
||||||
|
unset($changesets[$key]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$branch = $drequest->getBranchURIComponent(
|
||||||
|
$drequest->getBranch());
|
||||||
|
$filename = $changeset->getFilename();
|
||||||
|
$commit = $drequest->getCommit();
|
||||||
|
$reference = "{$branch}{$filename};{$commit}";
|
||||||
|
$references[$key] = $reference;
|
||||||
|
}
|
||||||
|
|
||||||
|
$change_list = new DifferentialChangesetListView();
|
||||||
|
$change_list->setChangesets($changesets);
|
||||||
|
$change_list->setRenderingReferences($references);
|
||||||
|
$change_list->setRenderURI('/diffusion/'.$callsign.'/diff/');
|
||||||
|
|
||||||
|
// TODO: This is pretty awkward, unify the CSS between Diffusion and
|
||||||
|
// Differential better.
|
||||||
|
require_celerity_resource('differential-core-view-css');
|
||||||
|
$change_list =
|
||||||
|
'<div class="differential-primary-pane">'.
|
||||||
|
$change_list->render().
|
||||||
|
'</div>';
|
||||||
|
|
||||||
$content[] = $change_list;
|
$content[] = $change_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,11 +25,12 @@ abstract class DiffusionBrowseQuery {
|
||||||
protected $deletedAtCommit;
|
protected $deletedAtCommit;
|
||||||
protected $validityOnly;
|
protected $validityOnly;
|
||||||
|
|
||||||
const REASON_IS_FILE = 'is-file';
|
const REASON_IS_FILE = 'is-file';
|
||||||
const REASON_IS_DELETED = 'is-deleted';
|
const REASON_IS_DELETED = 'is-deleted';
|
||||||
const REASON_IS_NONEXISTENT = 'nonexistent';
|
const REASON_IS_NONEXISTENT = 'nonexistent';
|
||||||
const REASON_BAD_COMMIT = 'bad-commit';
|
const REASON_BAD_COMMIT = 'bad-commit';
|
||||||
const REASON_IS_EMPTY = 'empty';
|
const REASON_IS_EMPTY = 'empty';
|
||||||
|
const REASON_IS_UNTRACKED_PARENT = 'untracked-parent';
|
||||||
|
|
||||||
final private function __construct() {
|
final private function __construct() {
|
||||||
// <private>
|
// <private>
|
||||||
|
|
|
@ -25,6 +25,15 @@ final class DiffusionSvnBrowseQuery extends DiffusionBrowseQuery {
|
||||||
$path = $drequest->getPath();
|
$path = $drequest->getPath();
|
||||||
$commit = $drequest->getCommit();
|
$commit = $drequest->getCommit();
|
||||||
|
|
||||||
|
$subpath = $repository->getDetail('svn-subpath');
|
||||||
|
if ($subpath && strncmp($subpath, $path, strlen($subpath))) {
|
||||||
|
// If we have a subpath and the path isn't a child of it, it (almost
|
||||||
|
// certainly) won't exist since we don't track commits which affect
|
||||||
|
// it. (Even if it exists, return a consistent result.)
|
||||||
|
$this->reason = self::REASON_IS_UNTRACKED_PARENT;
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
$conn_r = $repository->establishConnection('r');
|
$conn_r = $repository->establishConnection('r');
|
||||||
|
|
||||||
$parent_path = dirname($path);
|
$parent_path = dirname($path);
|
||||||
|
|
|
@ -140,9 +140,9 @@ final class DiffusionSvnDiffQuery extends DiffusionDiffQuery {
|
||||||
$repository = $drequest->getRepository();
|
$repository = $drequest->getRepository();
|
||||||
|
|
||||||
list($ref, $rev) = $spec;
|
list($ref, $rev) = $spec;
|
||||||
return new ExecFuture(
|
return $repository->getRemoteCommandFuture(
|
||||||
'svn --non-interactive cat %s%s@%d',
|
'cat %s%s@%d',
|
||||||
$repository->getDetail('remote-uri'),
|
$repository->getRemoteURI(),
|
||||||
$ref,
|
$ref,
|
||||||
$rev);
|
$rev);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@ phutil_require_module('phabricator', 'applications/diffusion/query/pathchange/ba
|
||||||
phutil_require_module('phabricator', 'infrastructure/diff/engine');
|
phutil_require_module('phabricator', 'infrastructure/diff/engine');
|
||||||
|
|
||||||
phutil_require_module('phutil', 'future');
|
phutil_require_module('phutil', 'future');
|
||||||
phutil_require_module('phutil', 'future/exec');
|
|
||||||
phutil_require_module('phutil', 'utils');
|
phutil_require_module('phutil', 'utils');
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -33,11 +33,11 @@ final class DiffusionSvnFileContentQuery extends DiffusionFileContentQuery {
|
||||||
$path = $drequest->getPath();
|
$path = $drequest->getPath();
|
||||||
$commit = $drequest->getCommit();
|
$commit = $drequest->getCommit();
|
||||||
|
|
||||||
$remote_uri = $repository->getDetail('remote-uri');
|
$remote_uri = $repository->getRemoteURI();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
list($corpus) = execx(
|
list($corpus) = $repository->execxRemoteCommand(
|
||||||
'svn --non-interactive %s %s%s@%s',
|
'%s %s%s@%s',
|
||||||
$this->getNeedsBlame() ? 'blame' : 'cat',
|
$this->getNeedsBlame() ? 'blame' : 'cat',
|
||||||
$remote_uri,
|
$remote_uri,
|
||||||
$path,
|
$path,
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
phutil_require_module('phabricator', 'applications/diffusion/data/filecontent');
|
phutil_require_module('phabricator', 'applications/diffusion/data/filecontent');
|
||||||
phutil_require_module('phabricator', 'applications/diffusion/query/filecontent/base');
|
phutil_require_module('phabricator', 'applications/diffusion/query/filecontent/base');
|
||||||
|
|
||||||
phutil_require_module('phutil', 'future/exec');
|
|
||||||
phutil_require_module('phutil', 'utils');
|
phutil_require_module('phutil', 'utils');
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,14 @@ class DiffusionSvnRequest extends DiffusionRequest {
|
||||||
|
|
||||||
protected function initializeFromAphrontRequestDictionary(array $data) {
|
protected function initializeFromAphrontRequestDictionary(array $data) {
|
||||||
parent::initializeFromAphrontRequestDictionary($data);
|
parent::initializeFromAphrontRequestDictionary($data);
|
||||||
|
|
||||||
|
if ($this->path === null) {
|
||||||
|
$subpath = $this->repository->getDetail('svn-subpath');
|
||||||
|
if ($subpath) {
|
||||||
|
$this->path = $subpath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!strncmp($this->path, ':', 1)) {
|
if (!strncmp($this->path, ':', 1)) {
|
||||||
$this->path = substr($this->path, 1);
|
$this->path = substr($this->path, 1);
|
||||||
$this->path = ltrim($this->path, '/');
|
$this->path = ltrim($this->path, '/');
|
||||||
|
|
|
@ -24,6 +24,7 @@ final class PhabricatorContentSource {
|
||||||
const SOURCE_CONDUIT = 'conduit';
|
const SOURCE_CONDUIT = 'conduit';
|
||||||
const SOURCE_MOBILE = 'mobile';
|
const SOURCE_MOBILE = 'mobile';
|
||||||
const SOURCE_TABLET = 'tablet';
|
const SOURCE_TABLET = 'tablet';
|
||||||
|
const SOURCE_FAX = 'fax';
|
||||||
|
|
||||||
private $source;
|
private $source;
|
||||||
private $params = array();
|
private $params = array();
|
||||||
|
|
|
@ -35,13 +35,13 @@ final class PhabricatorContentSourceView extends AphrontView {
|
||||||
public function render() {
|
public function render() {
|
||||||
require_celerity_resource('phabricator-content-source-view-css');
|
require_celerity_resource('phabricator-content-source-view-css');
|
||||||
|
|
||||||
$type = null;
|
|
||||||
$map = array(
|
$map = array(
|
||||||
PhabricatorContentSource::SOURCE_WEB => 'web',
|
PhabricatorContentSource::SOURCE_WEB => 'Web',
|
||||||
PhabricatorContentSource::SOURCE_CONDUIT => 'conduit',
|
PhabricatorContentSource::SOURCE_CONDUIT => 'Conduit',
|
||||||
PhabricatorContentSource::SOURCE_EMAIL => 'email',
|
PhabricatorContentSource::SOURCE_EMAIL => 'Email',
|
||||||
PhabricatorContentSource::SOURCE_MOBILE => 'mobile',
|
PhabricatorContentSource::SOURCE_MOBILE => 'Mobile',
|
||||||
PhabricatorContentSource::SOURCE_TABLET => 'tablet',
|
PhabricatorContentSource::SOURCE_TABLET => 'Tablet',
|
||||||
|
PhabricatorContentSource::SOURCE_FAX => 'Fax',
|
||||||
);
|
);
|
||||||
|
|
||||||
$source = $this->contentSource->getSource();
|
$source = $this->contentSource->getSource();
|
||||||
|
@ -51,14 +51,12 @@ final class PhabricatorContentSourceView extends AphrontView {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$type_class = 'phabricator-content-source-'.$type;
|
|
||||||
|
|
||||||
return phutil_render_tag(
|
return phutil_render_tag(
|
||||||
'span',
|
'span',
|
||||||
array(
|
array(
|
||||||
'class' => "phabricator-content-source-view {$type_class}",
|
'class' => "phabricator-content-source-view",
|
||||||
),
|
),
|
||||||
'Via');
|
"Via {$type}");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,16 +29,20 @@ class PhabricatorUserSettingsController extends PhabricatorPeopleController {
|
||||||
|
|
||||||
$request = $this->getRequest();
|
$request = $this->getRequest();
|
||||||
|
|
||||||
// TODO: Implement a password panel.
|
|
||||||
|
|
||||||
$this->pages = array(
|
$this->pages = array(
|
||||||
'account' => 'Account',
|
'account' => 'Account',
|
||||||
'profile' => 'Profile',
|
'profile' => 'Profile',
|
||||||
'email' => 'Email',
|
'email' => 'Email',
|
||||||
|
'password' => 'Password',
|
||||||
'preferences' => 'Preferences',
|
'preferences' => 'Preferences',
|
||||||
'conduit' => 'Conduit Certificate',
|
'conduit' => 'Conduit Certificate',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!PhabricatorEnv::getEnvConfig('account.editable') ||
|
||||||
|
!PhabricatorEnv::getEnvConfig('auth.password-auth-enabled')) {
|
||||||
|
unset($this->pages['password']);
|
||||||
|
}
|
||||||
|
|
||||||
if (PhabricatorUserSSHKeysSettingsPanelController::isEnabled()) {
|
if (PhabricatorUserSSHKeysSettingsPanelController::isEnabled()) {
|
||||||
$this->pages['sshkeys'] = 'SSH Public Keys';
|
$this->pages['sshkeys'] = 'SSH Public Keys';
|
||||||
}
|
}
|
||||||
|
@ -67,6 +71,10 @@ class PhabricatorUserSettingsController extends PhabricatorPeopleController {
|
||||||
case 'email':
|
case 'email':
|
||||||
$delegate = new PhabricatorUserEmailSettingsPanelController($request);
|
$delegate = new PhabricatorUserEmailSettingsPanelController($request);
|
||||||
break;
|
break;
|
||||||
|
case 'password':
|
||||||
|
$delegate = new PhabricatorUserPasswordSettingsPanelController(
|
||||||
|
$request);
|
||||||
|
break;
|
||||||
case 'conduit':
|
case 'conduit':
|
||||||
$delegate = new PhabricatorUserConduitSettingsPanelController($request);
|
$delegate = new PhabricatorUserConduitSettingsPanelController($request);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -13,9 +13,11 @@ phutil_require_module('phabricator', 'applications/people/controller/settings/pa
|
||||||
phutil_require_module('phabricator', 'applications/people/controller/settings/panels/conduit');
|
phutil_require_module('phabricator', 'applications/people/controller/settings/panels/conduit');
|
||||||
phutil_require_module('phabricator', 'applications/people/controller/settings/panels/email');
|
phutil_require_module('phabricator', 'applications/people/controller/settings/panels/email');
|
||||||
phutil_require_module('phabricator', 'applications/people/controller/settings/panels/oauth');
|
phutil_require_module('phabricator', 'applications/people/controller/settings/panels/oauth');
|
||||||
|
phutil_require_module('phabricator', 'applications/people/controller/settings/panels/password');
|
||||||
phutil_require_module('phabricator', 'applications/people/controller/settings/panels/preferences');
|
phutil_require_module('phabricator', 'applications/people/controller/settings/panels/preferences');
|
||||||
phutil_require_module('phabricator', 'applications/people/controller/settings/panels/profile');
|
phutil_require_module('phabricator', 'applications/people/controller/settings/panels/profile');
|
||||||
phutil_require_module('phabricator', 'applications/people/controller/settings/panels/sshkeys');
|
phutil_require_module('phabricator', 'applications/people/controller/settings/panels/sshkeys');
|
||||||
|
phutil_require_module('phabricator', 'infrastructure/env');
|
||||||
phutil_require_module('phabricator', 'view/layout/sidenav');
|
phutil_require_module('phabricator', 'view/layout/sidenav');
|
||||||
|
|
||||||
phutil_require_module('phutil', 'markup');
|
phutil_require_module('phutil', 'markup');
|
||||||
|
|
|
@ -0,0 +1,111 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2011 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class PhabricatorUserPasswordSettingsPanelController
|
||||||
|
extends PhabricatorUserSettingsPanelController {
|
||||||
|
|
||||||
|
public function processRequest() {
|
||||||
|
|
||||||
|
$request = $this->getRequest();
|
||||||
|
$user = $request->getUser();
|
||||||
|
$editable = $this->getAccountEditable();
|
||||||
|
|
||||||
|
// There's no sense in showing a change password panel if the user
|
||||||
|
// can't change their password
|
||||||
|
if (!$editable ||
|
||||||
|
!PhabricatorEnv::getEnvConfig('auth.password-auth-enabled')) {
|
||||||
|
return new Aphront400Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
$errors = array();
|
||||||
|
if ($request->isFormPost()) {
|
||||||
|
if ($user->comparePassword($request->getStr('old_pw'))) {
|
||||||
|
$pass = $request->getStr('new_pw');
|
||||||
|
$conf = $request->getStr('conf_pw');
|
||||||
|
if ($pass === $conf) {
|
||||||
|
if (strlen($pass)) {
|
||||||
|
$user->setPassword($pass);
|
||||||
|
// This write is unguarded because the CSRF token has already
|
||||||
|
// been checked in the call to $request->isFormPost() and
|
||||||
|
// the CSRF token depends on the password hash, so when it
|
||||||
|
// is changed here the CSRF token check will fail.
|
||||||
|
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
||||||
|
$user->save();
|
||||||
|
unset($unguarded);
|
||||||
|
return id(new AphrontRedirectResponse())
|
||||||
|
->setURI('/settings/page/password/?saved=true');
|
||||||
|
} else {
|
||||||
|
$errors[] = 'Your new password is too short.';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$errors[] = 'New password and confirmation do not match.';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$errors[] = 'The old password you entered is incorrect.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$notice = null;
|
||||||
|
if (!$errors) {
|
||||||
|
if ($request->getStr('saved')) {
|
||||||
|
$notice = new AphrontErrorView();
|
||||||
|
$notice->setSeverity(AphrontErrorView::SEVERITY_NOTICE);
|
||||||
|
$notice->setTitle('Changes Saved');
|
||||||
|
$notice->appendChild('<p>Your password has been updated.</p>');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$notice = new AphrontErrorView();
|
||||||
|
$notice->setTitle('Error Changing Password');
|
||||||
|
$notice->setErrors($errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
$form = new AphrontFormView();
|
||||||
|
$form
|
||||||
|
->setUser($user)
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormPasswordControl())
|
||||||
|
->setLabel('Old Password')
|
||||||
|
->setName('old_pw'));
|
||||||
|
$form
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormPasswordControl())
|
||||||
|
->setLabel('New Password')
|
||||||
|
->setName('new_pw'));
|
||||||
|
$form
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormPasswordControl())
|
||||||
|
->setLabel('Confirm Password')
|
||||||
|
->setName('conf_pw'));
|
||||||
|
$form
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormSubmitControl())
|
||||||
|
->setValue('Save'));
|
||||||
|
|
||||||
|
$panel = new AphrontPanelView();
|
||||||
|
$panel->setHeader('Change Password');
|
||||||
|
$panel->setWidth(AphrontPanelView::WIDTH_FORM);
|
||||||
|
$panel->appendChild($form);
|
||||||
|
|
||||||
|
return id(new AphrontNullView())
|
||||||
|
->appendChild(
|
||||||
|
array(
|
||||||
|
$notice,
|
||||||
|
$panel,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This file is automatically generated. Lint this module to rebuild it.
|
||||||
|
* @generated
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_module('phabricator', 'aphront/response/400');
|
||||||
|
phutil_require_module('phabricator', 'aphront/response/redirect');
|
||||||
|
phutil_require_module('phabricator', 'aphront/writeguard');
|
||||||
|
phutil_require_module('phabricator', 'applications/people/controller/settings/panels/base');
|
||||||
|
phutil_require_module('phabricator', 'infrastructure/env');
|
||||||
|
phutil_require_module('phabricator', 'view/form/base');
|
||||||
|
phutil_require_module('phabricator', 'view/form/control/password');
|
||||||
|
phutil_require_module('phabricator', 'view/form/control/submit');
|
||||||
|
phutil_require_module('phabricator', 'view/form/error');
|
||||||
|
phutil_require_module('phabricator', 'view/layout/panel');
|
||||||
|
phutil_require_module('phabricator', 'view/null');
|
||||||
|
|
||||||
|
phutil_require_module('phutil', 'utils');
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_source('PhabricatorUserPasswordSettingsPanelController.php');
|
|
@ -284,6 +284,16 @@ class PhabricatorUser extends PhabricatorUserDAO {
|
||||||
return $session_key;
|
return $session_key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function destroySession($session_key) {
|
||||||
|
$conn_w = $this->establishConnection('w');
|
||||||
|
queryfx(
|
||||||
|
$conn_w,
|
||||||
|
'DELETE FROM %T WHERE userPHID = %s AND sessionKey = %s',
|
||||||
|
self::SESSION_TABLE,
|
||||||
|
$this->getPHID(),
|
||||||
|
$session_key);
|
||||||
|
}
|
||||||
|
|
||||||
private function generateEmailToken($offset = 0) {
|
private function generateEmailToken($offset = 0) {
|
||||||
return $this->generateToken(
|
return $this->generateToken(
|
||||||
time() + ($offset * self::EMAIL_CYCLE_FREQUENCY),
|
time() + ($offset * self::EMAIL_CYCLE_FREQUENCY),
|
||||||
|
|
|
@ -205,6 +205,9 @@ class PhabricatorRepositoryEditController
|
||||||
$is_git = false;
|
$is_git = false;
|
||||||
$is_svn = false;
|
$is_svn = false;
|
||||||
|
|
||||||
|
$e_ssh_key = null;
|
||||||
|
$e_ssh_keyfile = null;
|
||||||
|
|
||||||
switch ($repository->getVersionControlSystem()) {
|
switch ($repository->getVersionControlSystem()) {
|
||||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
|
||||||
$is_git = true;
|
$is_git = true;
|
||||||
|
@ -239,6 +242,22 @@ class PhabricatorRepositoryEditController
|
||||||
'default-owners-path',
|
'default-owners-path',
|
||||||
'/'));
|
'/'));
|
||||||
|
|
||||||
|
$repository->setDetail('ssh-login', $request->getStr('ssh-login'));
|
||||||
|
$repository->setDetail('ssh-key', $request->getStr('ssh-key'));
|
||||||
|
$repository->setDetail('ssh-keyfile', $request->getStr('ssh-keyfile'));
|
||||||
|
|
||||||
|
$repository->setDetail('http-login', $request->getStr('http-login'));
|
||||||
|
$repository->setDetail('http-pass', $request->getStr('http-pass'));
|
||||||
|
|
||||||
|
if ($repository->getDetail('ssh-key') &&
|
||||||
|
$repository->getDetail('ssh-keyfile')) {
|
||||||
|
$errors[] =
|
||||||
|
"Specify only one of 'SSH Private Key' and 'SSH Private Key File', ".
|
||||||
|
"not both.";
|
||||||
|
$e_ssh_key = 'Choose Only One';
|
||||||
|
$e_ssh_keyfile = 'Choose Only One';
|
||||||
|
}
|
||||||
|
|
||||||
$repository->setDetail(
|
$repository->setDetail(
|
||||||
'herald-disabled',
|
'herald-disabled',
|
||||||
$request->getInt('herald-disabled', 0));
|
$request->getInt('herald-disabled', 0));
|
||||||
|
@ -329,10 +348,14 @@ class PhabricatorRepositoryEditController
|
||||||
'Differential, Diffusion, Herald, and other services. To enable '.
|
'Differential, Diffusion, Herald, and other services. To enable '.
|
||||||
'tracking for a repository, configure it here and then start (or '.
|
'tracking for a repository, configure it here and then start (or '.
|
||||||
'restart) the daemons. More information is available in the '.
|
'restart) the daemons. More information is available in the '.
|
||||||
'<strong>'.$user_guide_link.'</strong>.</p>')
|
'<strong>'.$user_guide_link.'</strong>.</p>');
|
||||||
|
|
||||||
|
$form
|
||||||
|
->appendChild(
|
||||||
|
'<h1>Basics</h1><div class="aphront-form-inset">')
|
||||||
->appendChild(
|
->appendChild(
|
||||||
id(new AphrontFormStaticControl())
|
id(new AphrontFormStaticControl())
|
||||||
->setLabel('Repository')
|
->setLabel('Repository Name')
|
||||||
->setValue($repository->getName()))
|
->setValue($repository->getName()))
|
||||||
->appendChild(
|
->appendChild(
|
||||||
id(new AphrontFormSelectControl())
|
id(new AphrontFormSelectControl())
|
||||||
|
@ -345,13 +368,19 @@ class PhabricatorRepositoryEditController
|
||||||
->setValue(
|
->setValue(
|
||||||
$repository->getDetail('tracking-enabled')
|
$repository->getDetail('tracking-enabled')
|
||||||
? 'enabled'
|
? 'enabled'
|
||||||
: 'disabled'));
|
: 'disabled'))
|
||||||
|
->appendChild('</div>');
|
||||||
|
|
||||||
|
$form->appendChild(
|
||||||
|
'<h1>Remote URI</h1>'.
|
||||||
|
'<div class="aphront-form-inset">');
|
||||||
|
|
||||||
$uri_label = 'Repository URI';
|
$uri_label = 'Repository URI';
|
||||||
if ($is_git) {
|
if ($is_git) {
|
||||||
$instructions =
|
$instructions =
|
||||||
'NOTE: The user the tracking daemon runs as must have permission to '.
|
'Enter the URI to clone this repository from. It should look like '.
|
||||||
'<tt>git clone</tt> from this URI.';
|
'<tt>git@github.com:example/example.git</tt> or '.
|
||||||
|
'<tt>ssh://user@host.com/git/example.git</tt>';
|
||||||
$form->appendChild(
|
$form->appendChild(
|
||||||
'<p class="aphront-form-instructions">'.$instructions.'</p>');
|
'<p class="aphront-form-instructions">'.$instructions.'</p>');
|
||||||
} else if ($is_svn) {
|
} else if ($is_svn) {
|
||||||
|
@ -360,10 +389,7 @@ class PhabricatorRepositoryEditController
|
||||||
'You can figure this out by running <tt>svn info</tt> and looking at '.
|
'You can figure this out by running <tt>svn info</tt> and looking at '.
|
||||||
'the value in the <tt>Repository Root</tt> field. It should be a URI '.
|
'the value in the <tt>Repository Root</tt> field. It should be a URI '.
|
||||||
'and look like <tt>http://svn.example.org/svn/</tt> or '.
|
'and look like <tt>http://svn.example.org/svn/</tt> or '.
|
||||||
'<tt>svn+ssh://svn.example.com/svnroot/</tt>.'.
|
'<tt>svn+ssh://svn.example.com/svnroot/</tt>';
|
||||||
'<br /><br />'.
|
|
||||||
'NOTE: The user the daemons run as must be able to execute '.
|
|
||||||
'<tt>svn log</tt> against this URI.';
|
|
||||||
$form->appendChild(
|
$form->appendChild(
|
||||||
'<p class="aphront-form-instructions">'.$instructions.'</p>');
|
'<p class="aphront-form-instructions">'.$instructions.'</p>');
|
||||||
$uri_label = 'Repository Root';
|
$uri_label = 'Repository Root';
|
||||||
|
@ -374,9 +400,85 @@ class PhabricatorRepositoryEditController
|
||||||
id(new AphrontFormTextControl())
|
id(new AphrontFormTextControl())
|
||||||
->setName('uri')
|
->setName('uri')
|
||||||
->setLabel($uri_label)
|
->setLabel($uri_label)
|
||||||
|
->setID('remote-uri')
|
||||||
->setValue($repository->getDetail('remote-uri'))
|
->setValue($repository->getDetail('remote-uri'))
|
||||||
->setError($e_uri));
|
->setError($e_uri));
|
||||||
|
|
||||||
|
$form->appendChild(
|
||||||
|
'<div class="aphront-form-instructions">'.
|
||||||
|
'If you want to connect to this repository over SSH, enter the '.
|
||||||
|
'username and private key to use. You can leave these fields blank if '.
|
||||||
|
'the repository does not use SSH.'.
|
||||||
|
' <strong>NOTE: This feature is not yet fully supported.</strong>'.
|
||||||
|
'</div>');
|
||||||
|
|
||||||
|
$form
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormTextControl())
|
||||||
|
->setName('ssh-login')
|
||||||
|
->setLabel('SSH User')
|
||||||
|
->setValue($repository->getDetail('ssh-login')))
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormTextAreaControl())
|
||||||
|
->setName('ssh-key')
|
||||||
|
->setLabel('SSH Private Key')
|
||||||
|
->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_SHORT)
|
||||||
|
->setValue($repository->getDetail('ssh-key'))
|
||||||
|
->setError($e_ssh_key)
|
||||||
|
->setCaption('Specify the entire private key, <em>or</em>...'))
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormTextControl())
|
||||||
|
->setName('ssh-keyfile')
|
||||||
|
->setLabel('SSH Private Key File')
|
||||||
|
->setValue($repository->getDetail('ssh-keyfile'))
|
||||||
|
->setError($e_ssh_keyfile)
|
||||||
|
->setCaption(
|
||||||
|
'...specify a path on disk where the daemon should '.
|
||||||
|
'look for a private key.'));
|
||||||
|
|
||||||
|
$supports_http = $is_svn;
|
||||||
|
|
||||||
|
if ($supports_http) {
|
||||||
|
$form
|
||||||
|
->appendChild(
|
||||||
|
'<div class="aphront-form-instructions">'.
|
||||||
|
'If you want to connect to this repository over HTTP Basic Auth, '.
|
||||||
|
'enter the username and password to use. You can leave these '.
|
||||||
|
'fields blank if the repository does not use HTTP Basic Auth.'.
|
||||||
|
' <strong>NOTE: This feature is not yet fully supported.</strong>'.
|
||||||
|
'</div>')
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormTextControl())
|
||||||
|
->setName('http-login')
|
||||||
|
->setLabel('HTTP Basic Login')
|
||||||
|
->setValue($repository->getDetail('http-login')))
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormTextControl())
|
||||||
|
->setName('http-pass')
|
||||||
|
->setLabel('HTTP Basic Password')
|
||||||
|
->setValue($repository->getDetail('http-pass')));
|
||||||
|
}
|
||||||
|
|
||||||
|
$form
|
||||||
|
->appendChild(
|
||||||
|
'<div class="aphront-form-important">'.
|
||||||
|
'To test your authentication configuration, <strong>save this '.
|
||||||
|
'form</strong> and then run this script:'.
|
||||||
|
'<code>'.
|
||||||
|
'phabricator/ $ ./scripts/repository/test_connection.php '.
|
||||||
|
phutil_escape_html($repository->getCallsign()).
|
||||||
|
'</code>'.
|
||||||
|
'This will verify that your configuration is correct and the '.
|
||||||
|
'daemons can connect to the remote repository and pull changes '.
|
||||||
|
'from it.'.
|
||||||
|
'</div>');
|
||||||
|
|
||||||
|
$form->appendChild('</div>');
|
||||||
|
|
||||||
|
$form->appendChild(
|
||||||
|
'<h1>Importing Repository Information</h1>'.
|
||||||
|
'<div class="aphront-form-inset">');
|
||||||
|
|
||||||
if ($is_git) {
|
if ($is_git) {
|
||||||
$form->appendChild(
|
$form->appendChild(
|
||||||
'<p class="aphront-form-instructions">Select a path on local disk '.
|
'<p class="aphront-form-instructions">Select a path on local disk '.
|
||||||
|
@ -415,6 +517,12 @@ class PhabricatorRepositoryEditController
|
||||||
'Number of seconds daemon should sleep between requests. Larger '.
|
'Number of seconds daemon should sleep between requests. Larger '.
|
||||||
'numbers reduce load but also decrease responsiveness.'));
|
'numbers reduce load but also decrease responsiveness.'));
|
||||||
|
|
||||||
|
$form->appendChild('</div>');
|
||||||
|
|
||||||
|
$form->appendChild(
|
||||||
|
'<h1>Application Configuration</h1>'.
|
||||||
|
'<div class="aphront-form-inset">');
|
||||||
|
|
||||||
if ($is_git) {
|
if ($is_git) {
|
||||||
$form
|
$form
|
||||||
->appendChild(
|
->appendChild(
|
||||||
|
@ -452,8 +560,8 @@ class PhabricatorRepositoryEditController
|
||||||
1 => 'Disabled - Do Not Send Email',
|
1 => 'Disabled - Do Not Send Email',
|
||||||
))
|
))
|
||||||
->setCaption(
|
->setCaption(
|
||||||
'You can temporarily disable Herald notifications when reparsing '.
|
'You can temporarily disable Herald commit notifications when '.
|
||||||
'a repository or importing a new repository.'));
|
'reparsing a repository or importing a new repository.'));
|
||||||
|
|
||||||
$parsers = id(new PhutilSymbolLoader())
|
$parsers = id(new PhutilSymbolLoader())
|
||||||
->setAncestorClass('PhabricatorRepositoryCommitMessageDetailParser')
|
->setAncestorClass('PhabricatorRepositoryCommitMessageDetailParser')
|
||||||
|
@ -487,10 +595,12 @@ class PhabricatorRepositoryEditController
|
||||||
->setCaption('Repository UUID from <tt>svn info</tt>.'));
|
->setCaption('Repository UUID from <tt>svn info</tt>.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$form->appendChild('</div>');
|
||||||
|
|
||||||
$form
|
$form
|
||||||
->appendChild(
|
->appendChild(
|
||||||
id(new AphrontFormSubmitControl())
|
id(new AphrontFormSubmitControl())
|
||||||
->setValue('Save'));
|
->setValue('Save Configuration'));
|
||||||
|
|
||||||
$panel = new AphrontPanelView();
|
$panel = new AphrontPanelView();
|
||||||
$panel->setHeader('Repository Tracking');
|
$panel->setHeader('Repository Tracking');
|
||||||
|
|
|
@ -28,9 +28,9 @@ class PhabricatorRepositorySvnCommitDiscoveryDaemon
|
||||||
}
|
}
|
||||||
|
|
||||||
$uri = $this->getBaseSVNLogURI();
|
$uri = $this->getBaseSVNLogURI();
|
||||||
list($xml) = execx(
|
list($xml) = $repository->execxRemoteCommand(
|
||||||
'svn log --xml --non-interactive --quiet --limit 1 %s@HEAD',
|
' log --xml --quiet --limit 1 %s@HEAD',
|
||||||
$uri);
|
$uri);
|
||||||
|
|
||||||
$results = $this->parseSVNLogXML($xml);
|
$results = $this->parseSVNLogXML($xml);
|
||||||
$commit = key($results);
|
$commit = key($results);
|
||||||
|
@ -47,6 +47,7 @@ class PhabricatorRepositorySvnCommitDiscoveryDaemon
|
||||||
|
|
||||||
private function discoverCommit($commit, $epoch) {
|
private function discoverCommit($commit, $epoch) {
|
||||||
$uri = $this->getBaseSVNLogURI();
|
$uri = $this->getBaseSVNLogURI();
|
||||||
|
$repository = $this->getRepository();
|
||||||
|
|
||||||
$discover = array(
|
$discover = array(
|
||||||
$commit => $epoch,
|
$commit => $epoch,
|
||||||
|
@ -58,8 +59,8 @@ class PhabricatorRepositorySvnCommitDiscoveryDaemon
|
||||||
// Find all the unknown commits on this path. Note that we permit
|
// Find all the unknown commits on this path. Note that we permit
|
||||||
// importing an SVN subdirectory rather than the entire repository, so
|
// importing an SVN subdirectory rather than the entire repository, so
|
||||||
// commits may be nonsequential.
|
// commits may be nonsequential.
|
||||||
list($err, $xml, $stderr) = exec_manual(
|
list($err, $xml, $stderr) = $repository->execRemoteCommand(
|
||||||
'svn log --xml --non-interactive --quiet --limit %d %s@%d',
|
' log --xml --quiet --limit %d %s@%d',
|
||||||
$limit,
|
$limit,
|
||||||
$uri,
|
$uri,
|
||||||
$upper_bound - 1);
|
$upper_bound - 1);
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
phutil_require_module('phabricator', 'applications/repository/constants/repositorytype');
|
phutil_require_module('phabricator', 'applications/repository/constants/repositorytype');
|
||||||
phutil_require_module('phabricator', 'applications/repository/daemon/commitdiscovery/base');
|
phutil_require_module('phabricator', 'applications/repository/daemon/commitdiscovery/base');
|
||||||
|
|
||||||
phutil_require_module('phutil', 'future/exec');
|
|
||||||
phutil_require_module('phutil', 'utils');
|
phutil_require_module('phutil', 'utils');
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,8 @@ class PhabricatorRepository extends PhabricatorRepositoryDAO {
|
||||||
protected $versionControlSystem;
|
protected $versionControlSystem;
|
||||||
protected $details = array();
|
protected $details = array();
|
||||||
|
|
||||||
|
private $sshKeyfile;
|
||||||
|
|
||||||
public function getConfiguration() {
|
public function getConfiguration() {
|
||||||
return array(
|
return array(
|
||||||
self::CONFIG_AUX_PHID => true,
|
self::CONFIG_AUX_PHID => true,
|
||||||
|
@ -55,4 +57,240 @@ class PhabricatorRepository extends PhabricatorRepositoryDAO {
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getRemoteURI() {
|
||||||
|
$raw_uri = $this->getDetail('remote-uri');
|
||||||
|
|
||||||
|
$vcs = $this->getVersionControlSystem();
|
||||||
|
$is_git = ($vcs == PhabricatorRepositoryType::REPOSITORY_TYPE_GIT);
|
||||||
|
|
||||||
|
// If there's no protocol (git implicit SSH) reformat the URI to be a
|
||||||
|
// normal URI. These git URIs look like "user@domain.com:path" instead of
|
||||||
|
// "ssh://user@domain/path".
|
||||||
|
$uri = new PhutilURI($raw_uri);
|
||||||
|
if ($is_git && !$uri->getProtocol()) {
|
||||||
|
list($domain, $path) = explode(':', $raw_uri, 2);
|
||||||
|
$uri = new PhutilURI('ssh://'.$domain.'/'.$path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->isSSHProtocol($uri->getProtocol())) {
|
||||||
|
if ($this->getSSHLogin()) {
|
||||||
|
$uri->setUser($this->getSSHLogin());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (string)$uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLocalPath() {
|
||||||
|
return $this->getDetail('local-path');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execRemoteCommand($pattern /*, $arg, ... */) {
|
||||||
|
$args = func_get_args();
|
||||||
|
$args = $this->formatRemoteCommand($args);
|
||||||
|
return call_user_func_array('exec_manual', $args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execxRemoteCommand($pattern /*, $arg, ... */) {
|
||||||
|
$args = func_get_args();
|
||||||
|
$args = $this->formatRemoteCommand($args);
|
||||||
|
return call_user_func_array('execx', $args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRemoteCommandFuture($pattern /*, $arg, ... */) {
|
||||||
|
$args = func_get_args();
|
||||||
|
$args = $this->formatRemoteCommand($args);
|
||||||
|
return newv('ExecFuture', $args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function passthruRemoteCommand($pattern /*, $arg, ... */) {
|
||||||
|
$args = func_get_args();
|
||||||
|
$args = $this->formatRemoteCommand($args);
|
||||||
|
return call_user_func_array('phutil_passthru', $args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execLocalCommand($pattern /*, $arg, ... */) {
|
||||||
|
$args = func_get_args();
|
||||||
|
$args = $this->formatLocalCommand($args);
|
||||||
|
return call_user_func_array('exec_manual', $args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execxLocalCommand($pattern /*, $arg, ... */) {
|
||||||
|
$args = func_get_args();
|
||||||
|
$args = $this->formatLocalCommand($args);
|
||||||
|
return call_user_func_array('execx', $args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLocalCommandFuture($pattern /*, $arg, ... */) {
|
||||||
|
$args = func_get_args();
|
||||||
|
$args = $this->formatLocalCommand($args);
|
||||||
|
return newv('ExecFuture', $args);
|
||||||
|
|
||||||
|
}
|
||||||
|
public function passthruLocalCommand($pattern /*, $arg, ... */) {
|
||||||
|
$args = func_get_args();
|
||||||
|
$args = $this->formatLocalCommand($args);
|
||||||
|
return call_user_func_array('phutil_passthru', $args);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function formatRemoteCommand(array $args) {
|
||||||
|
$pattern = $args[0];
|
||||||
|
$args = array_slice($args, 1);
|
||||||
|
|
||||||
|
if ($this->shouldUseSSH()) {
|
||||||
|
switch ($this->getVersionControlSystem()) {
|
||||||
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
|
||||||
|
$pattern = "SVN_SSH=%s svn --non-interactive {$pattern}";
|
||||||
|
array_unshift(
|
||||||
|
$args,
|
||||||
|
csprintf(
|
||||||
|
'ssh -l %s -i %s',
|
||||||
|
$this->getSSHLogin(),
|
||||||
|
$this->getSSHKeyfile()));
|
||||||
|
break;
|
||||||
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
|
||||||
|
$command = call_user_func_array(
|
||||||
|
'csprintf',
|
||||||
|
array_merge(
|
||||||
|
array(
|
||||||
|
"(ssh-add %s && git {$pattern})",
|
||||||
|
$this->getSSHKeyfile(),
|
||||||
|
),
|
||||||
|
$args));
|
||||||
|
$pattern = "ssh-agent sh -c %s";
|
||||||
|
$args = array($command);
|
||||||
|
break;
|
||||||
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
|
||||||
|
$pattern = "hg --config ui.ssh=%s {$pattern}";
|
||||||
|
array_unshift(
|
||||||
|
$args,
|
||||||
|
csprintf(
|
||||||
|
'ssh -l %s -i %s',
|
||||||
|
$this->getSSHLogin(),
|
||||||
|
$this->getSSHKeyfile()));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception("Unrecognized version control system.");
|
||||||
|
}
|
||||||
|
} else if ($this->shouldUseHTTP()) {
|
||||||
|
switch ($this->getVersionControlSystem()) {
|
||||||
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
|
||||||
|
$pattern =
|
||||||
|
"svn ".
|
||||||
|
"--non-interactive ".
|
||||||
|
"--no-auth-cache ".
|
||||||
|
"--trust-server-cert ".
|
||||||
|
"--username %s ".
|
||||||
|
"--password %s ".
|
||||||
|
$pattern;
|
||||||
|
array_unshift(
|
||||||
|
$args,
|
||||||
|
$this->getDetail('http-login'),
|
||||||
|
$this->getDetail('http-pass'));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception(
|
||||||
|
"No support for HTTP Basic Auth in this version control system.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch ($this->getVersionControlSystem()) {
|
||||||
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
|
||||||
|
$pattern = "svn --non-interactive {$pattern}";
|
||||||
|
break;
|
||||||
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
|
||||||
|
$pattern = "git {$pattern}";
|
||||||
|
break;
|
||||||
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
|
||||||
|
$pattern = "hg {$pattern}";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception("Unrecognized version control system.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
array_unshift($args, $pattern);
|
||||||
|
|
||||||
|
return $args;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function formatLocalCommand(array $args) {
|
||||||
|
$pattern = $args[0];
|
||||||
|
$args = array_slice($args, 1);
|
||||||
|
|
||||||
|
switch ($this->getVersionControlSystem()) {
|
||||||
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
|
||||||
|
$pattern = "(cd %s && svn --non-interactive {$pattern})";
|
||||||
|
array_unshift($args, $this->getLocalPath());
|
||||||
|
break;
|
||||||
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
|
||||||
|
$pattern = "(cd %s && git {$pattern})";
|
||||||
|
array_unshift($args, $this->getLocalPath());
|
||||||
|
break;
|
||||||
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
|
||||||
|
$pattern = "(cd %s && hg {$pattern})";
|
||||||
|
array_unshift($args, $this->getLocalPath());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception("Unrecognized version control system.");
|
||||||
|
}
|
||||||
|
|
||||||
|
array_unshift($args, $pattern);
|
||||||
|
|
||||||
|
return $args;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getSSHLogin() {
|
||||||
|
return $this->getDetail('ssh-login');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getSSHKeyfile() {
|
||||||
|
if ($this->sshKeyfile === null) {
|
||||||
|
$key = $this->getDetail('ssh-key');
|
||||||
|
$keyfile = $this->getDetail('ssh-keyfile');
|
||||||
|
if ($keyfile) {
|
||||||
|
// Make sure we can read the file, that it exists, etc.
|
||||||
|
Filesystem::readFile($keyfile);
|
||||||
|
$this->sshKeyfile = $keyfile;
|
||||||
|
} else if ($key) {
|
||||||
|
$keyfile = new TempFile('phabricator-repository-ssh-key');
|
||||||
|
chmod($keyfile, 0600);
|
||||||
|
Filesystem::writeFile($keyfile, $key);
|
||||||
|
$this->sshKeyfile = $keyfile;
|
||||||
|
} else {
|
||||||
|
$this->sshKeyfile = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (string)$this->sshKeyfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function shouldUseSSH() {
|
||||||
|
$uri = new PhutilURI($this->getRemoteURI());
|
||||||
|
$protocol = $uri->getProtocol();
|
||||||
|
if ($this->isSSHProtocol($protocol)) {
|
||||||
|
return (bool)$this->getSSHKeyfile();
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function shouldUseHTTP() {
|
||||||
|
$uri = new PhutilURI($this->getRemoteURI());
|
||||||
|
$protocol = $uri->getProtocol();
|
||||||
|
if ($this->isHTTPProtocol($protocol)) {
|
||||||
|
return (bool)$this->getDetail('http-login');
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function isSSHProtocol($protocol) {
|
||||||
|
return ($protocol == 'ssh' || $protocol == 'svn+ssh');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function isHTTPProtocol($protocol) {
|
||||||
|
return ($protocol == 'http' || $protocol == 'https');
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,15 @@
|
||||||
|
|
||||||
phutil_require_module('phabricator', 'applications/phid/constants');
|
phutil_require_module('phabricator', 'applications/phid/constants');
|
||||||
phutil_require_module('phabricator', 'applications/phid/storage/phid');
|
phutil_require_module('phabricator', 'applications/phid/storage/phid');
|
||||||
|
phutil_require_module('phabricator', 'applications/repository/constants/repositorytype');
|
||||||
phutil_require_module('phabricator', 'applications/repository/storage/base');
|
phutil_require_module('phabricator', 'applications/repository/storage/base');
|
||||||
|
|
||||||
|
phutil_require_module('phutil', 'filesystem');
|
||||||
|
phutil_require_module('phutil', 'filesystem/tempfile');
|
||||||
|
phutil_require_module('phutil', 'future/exec');
|
||||||
|
phutil_require_module('phutil', 'parser/uri');
|
||||||
phutil_require_module('phutil', 'utils');
|
phutil_require_module('phutil', 'utils');
|
||||||
|
phutil_require_module('phutil', 'xsprintf/csprintf');
|
||||||
|
|
||||||
|
|
||||||
phutil_require_source('PhabricatorRepository.php');
|
phutil_require_source('PhabricatorRepository.php');
|
||||||
|
|
|
@ -68,8 +68,8 @@ abstract class PhabricatorRepositoryCommitParserWorker
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
list($xml) = execx(
|
list($xml) = $this->repository->execxRemoteCommand(
|
||||||
"svn log --xml {$verbose} --limit 1 --non-interactive %s@%d",
|
"log --xml {$verbose} --limit 1 %s@%d",
|
||||||
$uri,
|
$uri,
|
||||||
$revision);
|
$revision);
|
||||||
} catch (CommandException $ex) {
|
} catch (CommandException $ex) {
|
||||||
|
|
|
@ -496,11 +496,59 @@ class PhabricatorRepositorySvnCommitChangeParserWorker
|
||||||
$commit_table = new PhabricatorRepositoryCommit();
|
$commit_table = new PhabricatorRepositoryCommit();
|
||||||
$commit_data = queryfx_all(
|
$commit_data = queryfx_all(
|
||||||
$commit_table->establishConnection('w'),
|
$commit_table->establishConnection('w'),
|
||||||
'SELECT id, commitIdentifier FROM %T WHERE commitIdentifier in (%Ld)',
|
'SELECT id, commitIdentifier FROM %T
|
||||||
|
WHERE repositoryID = %d AND commitIdentifier in (%Ld)',
|
||||||
$commit_table->getTableName(),
|
$commit_table->getTableName(),
|
||||||
|
$repository->getID(),
|
||||||
$commits);
|
$commits);
|
||||||
|
|
||||||
return ipull($commit_data, 'id', 'commitIdentifier');
|
$commit_map = ipull($commit_data, 'id', 'commitIdentifier');
|
||||||
|
|
||||||
|
$need = array();
|
||||||
|
foreach ($commits as $commit) {
|
||||||
|
if (empty($commit_map[$commit])) {
|
||||||
|
$need[] = $commit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we are parsing a Subversion repository and have been configured to
|
||||||
|
// import only some subdirectory of it, we may find commits which reference
|
||||||
|
// other foreign commits outside of the directory (for instance, because of
|
||||||
|
// a move or copy). Rather than trying to execute full parses on them, just
|
||||||
|
// create stub commits and identify the stubs as foreign commits.
|
||||||
|
if ($need) {
|
||||||
|
$subpath = $repository->getDetail('svn-subpath');
|
||||||
|
if (!$subpath) {
|
||||||
|
$commits = implode(', ', $need);
|
||||||
|
throw new Exception(
|
||||||
|
"Missing commits ({$need}) in a SVN repository which is not ".
|
||||||
|
"configured for subdirectory-only parsing!");
|
||||||
|
}
|
||||||
|
foreach ($need as $foreign_commit) {
|
||||||
|
$commit = new PhabricatorRepositoryCommit();
|
||||||
|
$commit->setRepositoryID($repository->getID());
|
||||||
|
$commit->setCommitIdentifier($foreign_commit);
|
||||||
|
$commit->setEpoch(0);
|
||||||
|
$commit->save();
|
||||||
|
|
||||||
|
$data = new PhabricatorRepositoryCommitData();
|
||||||
|
$data->setCommitID($commit->getID());
|
||||||
|
$data->setAuthorName('');
|
||||||
|
$data->setCommitMessage('');
|
||||||
|
$data->setCommitDetails(
|
||||||
|
array(
|
||||||
|
'foreign-svn-stub' => true,
|
||||||
|
// Denormalize this to make it easier to debug cases where someone
|
||||||
|
// did half a parse and then changed the subdirectory or something
|
||||||
|
// like that.
|
||||||
|
'svn-subpath' => $subpath,
|
||||||
|
));
|
||||||
|
$data->save();
|
||||||
|
$commit_map[$foreign_commit] = $commit->getID();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $commit_map;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function lookupPathFileType(
|
private function lookupPathFileType(
|
||||||
|
@ -545,10 +593,9 @@ class PhabricatorRepositorySvnCommitChangeParserWorker
|
||||||
// position in the document.
|
// position in the document.
|
||||||
$all_paths = array_reverse(array_keys($parents));
|
$all_paths = array_reverse(array_keys($parents));
|
||||||
foreach (array_chunk($all_paths, 64) as $path_chunk) {
|
foreach (array_chunk($all_paths, 64) as $path_chunk) {
|
||||||
list($raw_xml) = execx(
|
list($raw_xml) = $repository->execxRemoteCommand(
|
||||||
'svn --non-interactive --xml ls %C',
|
'--xml ls %C',
|
||||||
implode(' ', $path_chunk));
|
implode(' ', $path_chunk));
|
||||||
|
|
||||||
$xml = new SimpleXMLElement($raw_xml);
|
$xml = new SimpleXMLElement($raw_xml);
|
||||||
foreach ($xml->list as $list) {
|
foreach ($xml->list as $list) {
|
||||||
$list_path = (string)$list['path'];
|
$list_path = (string)$list['path'];
|
||||||
|
@ -621,8 +668,8 @@ class PhabricatorRepositorySvnCommitChangeParserWorker
|
||||||
$cache_loc = sys_get_temp_dir().'/diffusion.'.$hashkey.'.svnls';
|
$cache_loc = sys_get_temp_dir().'/diffusion.'.$hashkey.'.svnls';
|
||||||
if (!Filesystem::pathExists($cache_loc)) {
|
if (!Filesystem::pathExists($cache_loc)) {
|
||||||
$tmp = new TempFile();
|
$tmp = new TempFile();
|
||||||
execx(
|
$repository->execxRemoteCommand(
|
||||||
'svn --non-interactive --xml ls -R %s%s@%d > %s',
|
'--xml ls -R %s%s@%d > %s',
|
||||||
$repository->getDetail('remote-uri'),
|
$repository->getDetail('remote-uri'),
|
||||||
$path,
|
$path,
|
||||||
$rev,
|
$rev,
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
phutil_require_module('phabricator', 'applications/differential/constants/changetype');
|
phutil_require_module('phabricator', 'applications/differential/constants/changetype');
|
||||||
phutil_require_module('phabricator', 'applications/repository/storage/commit');
|
phutil_require_module('phabricator', 'applications/repository/storage/commit');
|
||||||
|
phutil_require_module('phabricator', 'applications/repository/storage/commitdata');
|
||||||
phutil_require_module('phabricator', 'applications/repository/storage/repository');
|
phutil_require_module('phabricator', 'applications/repository/storage/repository');
|
||||||
phutil_require_module('phabricator', 'applications/repository/worker/commitchangeparser/base');
|
phutil_require_module('phabricator', 'applications/repository/worker/commitchangeparser/base');
|
||||||
phutil_require_module('phabricator', 'storage/qsprintf');
|
phutil_require_module('phabricator', 'storage/qsprintf');
|
||||||
|
|
|
@ -145,6 +145,21 @@ class PhabricatorSetup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
list($err, $stdout, $stderr) = exec_manual(
|
||||||
|
'/usr/bin/env php -r %s',
|
||||||
|
'exit;');
|
||||||
|
if ($err) {
|
||||||
|
self::writeFailure();
|
||||||
|
self::write("Unable to execute 'php' on the command line from the web ".
|
||||||
|
"server. Verify that 'php' is in the webserver's PATH.\n".
|
||||||
|
" err: {$err}\n".
|
||||||
|
"stdout: {$stdout}\n".
|
||||||
|
"stderr: {$stderr}\n");
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
self::write(" okay PHP is available from the command line.\n");
|
||||||
|
}
|
||||||
|
|
||||||
$root = dirname(phutil_get_library_root('phabricator'));
|
$root = dirname(phutil_get_library_root('phabricator'));
|
||||||
|
|
||||||
// On RHEL6, doing a distro install of pcntl makes it available from the
|
// On RHEL6, doing a distro install of pcntl makes it available from the
|
||||||
|
|
|
@ -209,7 +209,7 @@ class AphrontMySQLDatabaseConnection extends AphrontDatabaseConnection {
|
||||||
$this->requireConnection();
|
$this->requireConnection();
|
||||||
|
|
||||||
// TODO: Do we need to include transactional statements here?
|
// TODO: Do we need to include transactional statements here?
|
||||||
$is_write = !preg_match('/^(SELECT|SHOW)\s/', $raw_query);
|
$is_write = !preg_match('/^(SELECT|SHOW|EXPLAIN)\s/', $raw_query);
|
||||||
if ($is_write) {
|
if ($is_write) {
|
||||||
AphrontWriteGuard::willWrite();
|
AphrontWriteGuard::willWrite();
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ final class AphrontFilePreviewView extends AphrontView {
|
||||||
$link = phutil_render_tag(
|
$link = phutil_render_tag(
|
||||||
'a',
|
'a',
|
||||||
array(
|
array(
|
||||||
'href' => $file->getViewURI(),
|
'href' => $file->getBestURI(),
|
||||||
'target' => '_blank',
|
'target' => '_blank',
|
||||||
),
|
),
|
||||||
$img);
|
$img);
|
||||||
|
|
|
@ -250,7 +250,7 @@ function phabricator_shutdown() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($event['type'] != E_ERROR) {
|
if ($event['type'] != E_ERROR && $event['type'] != E_PARSE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,6 +87,18 @@
|
||||||
margin: 0.75em 3% 1.25em;
|
margin: 0.75em 3% 1.25em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.aphront-form-important {
|
||||||
|
margin: .5em 0;
|
||||||
|
background: #ffffdd;
|
||||||
|
padding: .5em 1em;
|
||||||
|
}
|
||||||
|
.aphront-form-important code {
|
||||||
|
display: block;
|
||||||
|
padding: .25em;
|
||||||
|
margin: .5em 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.aphront-form-control-static .aphront-form-input {
|
.aphront-form-control-static .aphront-form-input {
|
||||||
padding-top: 4px;
|
padding-top: 4px;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
|
|
|
@ -3,30 +3,5 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.phabricator-content-source-view {
|
.phabricator-content-source-view {
|
||||||
padding: 2px 20px 2px 0;
|
|
||||||
font-size: 11px;
|
|
||||||
color: #888888;
|
color: #888888;
|
||||||
font-weight: normal;
|
|
||||||
background: no-repeat right center;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.phabricator-content-source-web {
|
|
||||||
background-image: url(/rsrc/image/icon/fatcow/source/web.png);
|
|
||||||
}
|
|
||||||
|
|
||||||
.phabricator-content-source-email {
|
|
||||||
background-image: url(/rsrc/image/icon/fatcow/source/email.png);
|
|
||||||
}
|
|
||||||
|
|
||||||
.phabricator-content-source-conduit {
|
|
||||||
background-image: url(/rsrc/image/icon/fatcow/source/conduit.png);
|
|
||||||
}
|
|
||||||
|
|
||||||
.phabricator-content-source-mobile {
|
|
||||||
background-image: url(/rsrc/image/icon/fatcow/source/mobile.png);
|
|
||||||
}
|
|
||||||
|
|
||||||
.phabricator-content-source-tablet {
|
|
||||||
background-image: url(/rsrc/image/icon/fatcow/source/tablet.png);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
.differential-panel {
|
.differential-panel {
|
||||||
margin: 25px 0;
|
margin: 25px 0;
|
||||||
max-width: 1118px;
|
max-width: 1120px;
|
||||||
border: 1px solid #666622;
|
border: 1px solid #666622;
|
||||||
background: #efefdf;
|
background: #efefdf;
|
||||||
padding: 15px 20px;
|
padding: 15px 20px;
|
||||||
|
|
|
@ -14,3 +14,4 @@ Some icons have been adapted from the FatCow set for use in Phabricator:
|
||||||
source/conduit.png (from satellite_dish.png)
|
source/conduit.png (from satellite_dish.png)
|
||||||
source/mobile.png (from phone.png)
|
source/mobile.png (from phone.png)
|
||||||
source/tablet.png (from tablet.png)
|
source/tablet.png (from tablet.png)
|
||||||
|
source/fax.png (from fax.png)
|
BIN
webroot/rsrc/image/icon/fatcow/source/fax.png
Normal file
BIN
webroot/rsrc/image/icon/fatcow/source/fax.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 600 B |
Loading…
Reference in a new issue