mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-22 13:30: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' =>
|
||||
array(
|
||||
'uri' => '/res/438fe316/rsrc/css/application/differential/core.css',
|
||||
'uri' => '/res/584d40e8/rsrc/css/application/differential/core.css',
|
||||
'type' => 'css',
|
||||
'requires' =>
|
||||
array(
|
||||
|
@ -1180,7 +1180,7 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'phabricator-content-source-view-css' =>
|
||||
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',
|
||||
'requires' =>
|
||||
array(
|
||||
|
@ -1419,7 +1419,7 @@ celerity_register_resource_map(array(
|
|||
'uri' => '/res/pkg/3dbf4083/javelin.pkg.js',
|
||||
'type' => 'js',
|
||||
),
|
||||
'3f2092d7' =>
|
||||
'7bf96a66' =>
|
||||
array(
|
||||
'name' => 'differential.pkg.css',
|
||||
'symbols' =>
|
||||
|
@ -1433,7 +1433,7 @@ celerity_register_resource_map(array(
|
|||
6 => 'differential-revision-add-comment-css',
|
||||
7 => 'differential-revision-comment-list-css',
|
||||
),
|
||||
'uri' => '/res/pkg/3f2092d7/differential.pkg.css',
|
||||
'uri' => '/res/pkg/7bf96a66/differential.pkg.css',
|
||||
'type' => 'css',
|
||||
),
|
||||
'95c67dcd' =>
|
||||
|
@ -1518,14 +1518,14 @@ celerity_register_resource_map(array(
|
|||
'aphront-table-view-css' => '70966590',
|
||||
'aphront-tokenizer-control-css' => '70966590',
|
||||
'aphront-typeahead-control-css' => '70966590',
|
||||
'differential-changeset-view-css' => '3f2092d7',
|
||||
'differential-core-view-css' => '3f2092d7',
|
||||
'differential-revision-add-comment-css' => '3f2092d7',
|
||||
'differential-revision-comment-css' => '3f2092d7',
|
||||
'differential-revision-comment-list-css' => '3f2092d7',
|
||||
'differential-revision-detail-css' => '3f2092d7',
|
||||
'differential-revision-history-css' => '3f2092d7',
|
||||
'differential-table-of-contents-css' => '3f2092d7',
|
||||
'differential-changeset-view-css' => '7bf96a66',
|
||||
'differential-core-view-css' => '7bf96a66',
|
||||
'differential-revision-add-comment-css' => '7bf96a66',
|
||||
'differential-revision-comment-css' => '7bf96a66',
|
||||
'differential-revision-comment-list-css' => '7bf96a66',
|
||||
'differential-revision-detail-css' => '7bf96a66',
|
||||
'differential-revision-history-css' => '7bf96a66',
|
||||
'differential-table-of-contents-css' => '7bf96a66',
|
||||
'diffusion-commit-view-css' => '03ef179e',
|
||||
'javelin-behavior' => '3dbf4083',
|
||||
'javelin-behavior-aphront-basic-tokenizer' => 'ac869011',
|
||||
|
|
|
@ -642,6 +642,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorUserLog' => 'applications/people/storage/log',
|
||||
'PhabricatorUserOAuthInfo' => 'applications/people/storage/useroauthinfo',
|
||||
'PhabricatorUserOAuthSettingsPanelController' => 'applications/people/controller/settings/panels/oauth',
|
||||
'PhabricatorUserPasswordSettingsPanelController' => 'applications/people/controller/settings/panels/password',
|
||||
'PhabricatorUserPreferenceSettingsPanelController' => 'applications/people/controller/settings/panels/preferences',
|
||||
'PhabricatorUserPreferences' => 'applications/people/storage/preferences',
|
||||
'PhabricatorUserProfile' => 'applications/people/storage/profile',
|
||||
|
@ -1222,6 +1223,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorUserLog' => 'PhabricatorUserDAO',
|
||||
'PhabricatorUserOAuthInfo' => 'PhabricatorUserDAO',
|
||||
'PhabricatorUserOAuthSettingsPanelController' => 'PhabricatorUserSettingsPanelController',
|
||||
'PhabricatorUserPasswordSettingsPanelController' => 'PhabricatorUserSettingsPanelController',
|
||||
'PhabricatorUserPreferenceSettingsPanelController' => 'PhabricatorUserSettingsPanelController',
|
||||
'PhabricatorUserPreferences' => 'PhabricatorUserDAO',
|
||||
'PhabricatorUserProfile' => 'PhabricatorUserDAO',
|
||||
|
|
|
@ -145,6 +145,22 @@ class AphrontRequest {
|
|||
|
||||
$valid = $this->getUser()->validateCSRFToken($token);
|
||||
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
|
||||
// internet for 6 hours, and then reconnect and immediately submit,
|
||||
// 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 ".
|
||||
"become invalid if you leave a page open for more than six hours ".
|
||||
"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;
|
||||
|
|
|
@ -39,7 +39,15 @@ class PhabricatorLogoutController extends PhabricatorAuthController {
|
|||
PhabricatorUserLog::ACTION_LOGOUT);
|
||||
$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');
|
||||
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI('/login/');
|
||||
}
|
||||
|
|
|
@ -91,8 +91,6 @@ class ConduitAPI_differential_getrevision_Method extends ConduitAPIMethod {
|
|||
$revision->getStatus()),
|
||||
'summary' => $revision->getSummary(),
|
||||
'testPlan' => $revision->getTestPlan(),
|
||||
'revertPlan' => $revision->getRevertPlan(),
|
||||
'blameRevision' => $revision->getBlameRevision(),
|
||||
'lineCount' => $revision->getLineCount(),
|
||||
'reviewerPHIDs' => $reviewer_phids,
|
||||
'diffs' => $diff_dicts,
|
||||
|
|
|
@ -46,6 +46,35 @@ class PhabricatorWorkerTaskDetailController
|
|||
$data = id(new PhabricatorWorkerTaskData())->loadOneWhere(
|
||||
'id = %d',
|
||||
$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) {
|
||||
$data = json_encode($data->getData());
|
||||
}
|
||||
|
@ -75,14 +104,23 @@ class PhabricatorWorkerTaskDetailController
|
|||
->appendChild(
|
||||
id(new AphrontFormTextAreaControl())
|
||||
->setLabel('Data')
|
||||
->setValue($data))
|
||||
->setValue($data));
|
||||
|
||||
if ($extra) {
|
||||
$form->appendChild(
|
||||
id(new AphrontFormMarkupControl())
|
||||
->setLabel('More')
|
||||
->setValue($extra));
|
||||
}
|
||||
|
||||
$form
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->addCancelButton('/daemon/'));
|
||||
|
||||
$panel = new AphrontPanelView();
|
||||
$panel->setHeader('Task Detail');
|
||||
$panel->setWidth(AphrontPanelView::WIDTH_FORM);
|
||||
$panel->setWidth(AphrontPanelView::WIDTH_WIDE);
|
||||
$panel->appendChild($form);
|
||||
|
||||
return $this->buildStandardPageResponse(
|
||||
|
|
|
@ -7,15 +7,19 @@
|
|||
|
||||
|
||||
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/taskdata');
|
||||
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/submit');
|
||||
phutil_require_module('phabricator', 'view/form/control/textarea');
|
||||
phutil_require_module('phabricator', 'view/form/error');
|
||||
phutil_require_module('phabricator', 'view/layout/panel');
|
||||
|
||||
phutil_require_module('phutil', 'markup');
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
|
|
|
@ -175,12 +175,6 @@ class DifferentialRevisionEditor {
|
|||
if ($revision->getAuthorPHID() === null) {
|
||||
$revision->setAuthorPHID($this->getActorPHID());
|
||||
}
|
||||
if ($revision->getRevertPlan() === null) {
|
||||
$revision->setRevertPlan('');
|
||||
}
|
||||
if ($revision->getBlameRevision() === null) {
|
||||
$revision->setBlameRevision('');
|
||||
}
|
||||
if ($revision->getSummary() === null) {
|
||||
$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(
|
||||
$this->changeset,
|
||||
'<tr>'.
|
||||
'<th></th>'.
|
||||
$th_old.
|
||||
'<td class="differential-old-image">'.
|
||||
'<div class="differential-image-stage">'.
|
||||
$old.
|
||||
'</div>'.
|
||||
'</td>'.
|
||||
'<th></th>'.
|
||||
$th_new.
|
||||
'<td class="differential-new-image">'.
|
||||
'<div class="differential-image-stage">'.
|
||||
$cur.
|
||||
'</div>'.
|
||||
'</td>'.
|
||||
'</tr>');
|
||||
'</tr>'.
|
||||
implode('', $html_old).
|
||||
implode('', $html_new));
|
||||
|
||||
return $output;
|
||||
case DifferentialChangeType::FILE_DIRECTORY:
|
||||
|
|
|
@ -23,8 +23,6 @@ class DifferentialRevision extends DifferentialDAO {
|
|||
|
||||
protected $summary;
|
||||
protected $testPlan;
|
||||
protected $revertPlan;
|
||||
protected $blameRevision;
|
||||
|
||||
protected $phid;
|
||||
protected $authorPHID;
|
||||
|
|
|
@ -75,6 +75,16 @@ class DiffusionBrowseController extends DiffusionController {
|
|||
$controller->setDiffusionRequest($drequest);
|
||||
return $this->delegateToController($controller);
|
||||
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:
|
||||
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/layout/panel');
|
||||
|
||||
phutil_require_module('phutil', 'markup');
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
|
|
|
@ -44,6 +44,21 @@ class DiffusionCommitController extends DiffusionController {
|
|||
|
||||
$commit_data = $drequest->loadCommitData();
|
||||
|
||||
$is_foreign = $commit_data->getCommitDetail('foreign-svn-stub');
|
||||
if ($is_foreign) {
|
||||
$subpath = $commit_data->getCommitDetail('svn-subpath');
|
||||
|
||||
$error_panel = new AphrontErrorView();
|
||||
$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();
|
||||
|
||||
require_celerity_resource('diffusion-commit-view-css');
|
||||
|
@ -69,6 +84,7 @@ class DiffusionCommitController extends DiffusionController {
|
|||
'</div>');
|
||||
|
||||
$content[] = $detail_panel;
|
||||
}
|
||||
|
||||
$change_query = DiffusionPathChangeQuery::newFromDiffusionRequest(
|
||||
$drequest);
|
||||
|
@ -103,6 +119,23 @@ class DiffusionCommitController extends DiffusionController {
|
|||
phutil_escape_html($bad_commit['description']));
|
||||
|
||||
$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 {
|
||||
$change_panel = new AphrontPanelView();
|
||||
$change_panel->setHeader("Changes (".number_format($count).")");
|
||||
|
@ -130,7 +163,6 @@ class DiffusionCommitController extends DiffusionController {
|
|||
|
||||
$content[] = $change_panel;
|
||||
|
||||
if ($changes) {
|
||||
$changesets = DiffusionPathChange::convertToDifferentialChangesets(
|
||||
$changes);
|
||||
|
||||
|
@ -176,13 +208,6 @@ class DiffusionCommitController extends DiffusionController {
|
|||
'<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>';
|
||||
}
|
||||
|
||||
$content[] = $change_list;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ abstract class DiffusionBrowseQuery {
|
|||
const REASON_IS_NONEXISTENT = 'nonexistent';
|
||||
const REASON_BAD_COMMIT = 'bad-commit';
|
||||
const REASON_IS_EMPTY = 'empty';
|
||||
const REASON_IS_UNTRACKED_PARENT = 'untracked-parent';
|
||||
|
||||
final private function __construct() {
|
||||
// <private>
|
||||
|
|
|
@ -25,6 +25,15 @@ final class DiffusionSvnBrowseQuery extends DiffusionBrowseQuery {
|
|||
$path = $drequest->getPath();
|
||||
$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');
|
||||
|
||||
$parent_path = dirname($path);
|
||||
|
|
|
@ -140,9 +140,9 @@ final class DiffusionSvnDiffQuery extends DiffusionDiffQuery {
|
|||
$repository = $drequest->getRepository();
|
||||
|
||||
list($ref, $rev) = $spec;
|
||||
return new ExecFuture(
|
||||
'svn --non-interactive cat %s%s@%d',
|
||||
$repository->getDetail('remote-uri'),
|
||||
return $repository->getRemoteCommandFuture(
|
||||
'cat %s%s@%d',
|
||||
$repository->getRemoteURI(),
|
||||
$ref,
|
||||
$rev);
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@ phutil_require_module('phabricator', 'applications/diffusion/query/pathchange/ba
|
|||
phutil_require_module('phabricator', 'infrastructure/diff/engine');
|
||||
|
||||
phutil_require_module('phutil', 'future');
|
||||
phutil_require_module('phutil', 'future/exec');
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
|
|
|
@ -33,11 +33,11 @@ final class DiffusionSvnFileContentQuery extends DiffusionFileContentQuery {
|
|||
$path = $drequest->getPath();
|
||||
$commit = $drequest->getCommit();
|
||||
|
||||
$remote_uri = $repository->getDetail('remote-uri');
|
||||
$remote_uri = $repository->getRemoteURI();
|
||||
|
||||
try {
|
||||
list($corpus) = execx(
|
||||
'svn --non-interactive %s %s%s@%s',
|
||||
list($corpus) = $repository->execxRemoteCommand(
|
||||
'%s %s%s@%s',
|
||||
$this->getNeedsBlame() ? 'blame' : 'cat',
|
||||
$remote_uri,
|
||||
$path,
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
phutil_require_module('phabricator', 'applications/diffusion/data/filecontent');
|
||||
phutil_require_module('phabricator', 'applications/diffusion/query/filecontent/base');
|
||||
|
||||
phutil_require_module('phutil', 'future/exec');
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
|
|
|
@ -20,6 +20,14 @@ class DiffusionSvnRequest extends DiffusionRequest {
|
|||
|
||||
protected function initializeFromAphrontRequestDictionary(array $data) {
|
||||
parent::initializeFromAphrontRequestDictionary($data);
|
||||
|
||||
if ($this->path === null) {
|
||||
$subpath = $this->repository->getDetail('svn-subpath');
|
||||
if ($subpath) {
|
||||
$this->path = $subpath;
|
||||
}
|
||||
}
|
||||
|
||||
if (!strncmp($this->path, ':', 1)) {
|
||||
$this->path = substr($this->path, 1);
|
||||
$this->path = ltrim($this->path, '/');
|
||||
|
|
|
@ -24,6 +24,7 @@ final class PhabricatorContentSource {
|
|||
const SOURCE_CONDUIT = 'conduit';
|
||||
const SOURCE_MOBILE = 'mobile';
|
||||
const SOURCE_TABLET = 'tablet';
|
||||
const SOURCE_FAX = 'fax';
|
||||
|
||||
private $source;
|
||||
private $params = array();
|
||||
|
|
|
@ -35,13 +35,13 @@ final class PhabricatorContentSourceView extends AphrontView {
|
|||
public function render() {
|
||||
require_celerity_resource('phabricator-content-source-view-css');
|
||||
|
||||
$type = null;
|
||||
$map = array(
|
||||
PhabricatorContentSource::SOURCE_WEB => 'web',
|
||||
PhabricatorContentSource::SOURCE_CONDUIT => 'conduit',
|
||||
PhabricatorContentSource::SOURCE_EMAIL => 'email',
|
||||
PhabricatorContentSource::SOURCE_MOBILE => 'mobile',
|
||||
PhabricatorContentSource::SOURCE_TABLET => 'tablet',
|
||||
PhabricatorContentSource::SOURCE_WEB => 'Web',
|
||||
PhabricatorContentSource::SOURCE_CONDUIT => 'Conduit',
|
||||
PhabricatorContentSource::SOURCE_EMAIL => 'Email',
|
||||
PhabricatorContentSource::SOURCE_MOBILE => 'Mobile',
|
||||
PhabricatorContentSource::SOURCE_TABLET => 'Tablet',
|
||||
PhabricatorContentSource::SOURCE_FAX => 'Fax',
|
||||
);
|
||||
|
||||
$source = $this->contentSource->getSource();
|
||||
|
@ -51,14 +51,12 @@ final class PhabricatorContentSourceView extends AphrontView {
|
|||
return;
|
||||
}
|
||||
|
||||
$type_class = 'phabricator-content-source-'.$type;
|
||||
|
||||
return phutil_render_tag(
|
||||
'span',
|
||||
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();
|
||||
|
||||
// TODO: Implement a password panel.
|
||||
|
||||
$this->pages = array(
|
||||
'account' => 'Account',
|
||||
'profile' => 'Profile',
|
||||
'email' => 'Email',
|
||||
'password' => 'Password',
|
||||
'preferences' => 'Preferences',
|
||||
'conduit' => 'Conduit Certificate',
|
||||
);
|
||||
|
||||
if (!PhabricatorEnv::getEnvConfig('account.editable') ||
|
||||
!PhabricatorEnv::getEnvConfig('auth.password-auth-enabled')) {
|
||||
unset($this->pages['password']);
|
||||
}
|
||||
|
||||
if (PhabricatorUserSSHKeysSettingsPanelController::isEnabled()) {
|
||||
$this->pages['sshkeys'] = 'SSH Public Keys';
|
||||
}
|
||||
|
@ -67,6 +71,10 @@ class PhabricatorUserSettingsController extends PhabricatorPeopleController {
|
|||
case 'email':
|
||||
$delegate = new PhabricatorUserEmailSettingsPanelController($request);
|
||||
break;
|
||||
case 'password':
|
||||
$delegate = new PhabricatorUserPasswordSettingsPanelController(
|
||||
$request);
|
||||
break;
|
||||
case 'conduit':
|
||||
$delegate = new PhabricatorUserConduitSettingsPanelController($request);
|
||||
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/email');
|
||||
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/profile');
|
||||
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('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;
|
||||
}
|
||||
|
||||
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) {
|
||||
return $this->generateToken(
|
||||
time() + ($offset * self::EMAIL_CYCLE_FREQUENCY),
|
||||
|
|
|
@ -205,6 +205,9 @@ class PhabricatorRepositoryEditController
|
|||
$is_git = false;
|
||||
$is_svn = false;
|
||||
|
||||
$e_ssh_key = null;
|
||||
$e_ssh_keyfile = null;
|
||||
|
||||
switch ($repository->getVersionControlSystem()) {
|
||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
|
||||
$is_git = true;
|
||||
|
@ -239,6 +242,22 @@ class PhabricatorRepositoryEditController
|
|||
'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(
|
||||
'herald-disabled',
|
||||
$request->getInt('herald-disabled', 0));
|
||||
|
@ -329,10 +348,14 @@ class PhabricatorRepositoryEditController
|
|||
'Differential, Diffusion, Herald, and other services. To enable '.
|
||||
'tracking for a repository, configure it here and then start (or '.
|
||||
'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(
|
||||
id(new AphrontFormStaticControl())
|
||||
->setLabel('Repository')
|
||||
->setLabel('Repository Name')
|
||||
->setValue($repository->getName()))
|
||||
->appendChild(
|
||||
id(new AphrontFormSelectControl())
|
||||
|
@ -345,13 +368,19 @@ class PhabricatorRepositoryEditController
|
|||
->setValue(
|
||||
$repository->getDetail('tracking-enabled')
|
||||
? 'enabled'
|
||||
: 'disabled'));
|
||||
: 'disabled'))
|
||||
->appendChild('</div>');
|
||||
|
||||
$form->appendChild(
|
||||
'<h1>Remote URI</h1>'.
|
||||
'<div class="aphront-form-inset">');
|
||||
|
||||
$uri_label = 'Repository URI';
|
||||
if ($is_git) {
|
||||
$instructions =
|
||||
'NOTE: The user the tracking daemon runs as must have permission to '.
|
||||
'<tt>git clone</tt> from this URI.';
|
||||
'Enter the URI to clone this repository from. It should look like '.
|
||||
'<tt>git@github.com:example/example.git</tt> or '.
|
||||
'<tt>ssh://user@host.com/git/example.git</tt>';
|
||||
$form->appendChild(
|
||||
'<p class="aphront-form-instructions">'.$instructions.'</p>');
|
||||
} else if ($is_svn) {
|
||||
|
@ -360,10 +389,7 @@ class PhabricatorRepositoryEditController
|
|||
'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 '.
|
||||
'and look like <tt>http://svn.example.org/svn/</tt> or '.
|
||||
'<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.';
|
||||
'<tt>svn+ssh://svn.example.com/svnroot/</tt>';
|
||||
$form->appendChild(
|
||||
'<p class="aphront-form-instructions">'.$instructions.'</p>');
|
||||
$uri_label = 'Repository Root';
|
||||
|
@ -374,9 +400,85 @@ class PhabricatorRepositoryEditController
|
|||
id(new AphrontFormTextControl())
|
||||
->setName('uri')
|
||||
->setLabel($uri_label)
|
||||
->setID('remote-uri')
|
||||
->setValue($repository->getDetail('remote-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) {
|
||||
$form->appendChild(
|
||||
'<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 '.
|
||||
'numbers reduce load but also decrease responsiveness.'));
|
||||
|
||||
$form->appendChild('</div>');
|
||||
|
||||
$form->appendChild(
|
||||
'<h1>Application Configuration</h1>'.
|
||||
'<div class="aphront-form-inset">');
|
||||
|
||||
if ($is_git) {
|
||||
$form
|
||||
->appendChild(
|
||||
|
@ -452,8 +560,8 @@ class PhabricatorRepositoryEditController
|
|||
1 => 'Disabled - Do Not Send Email',
|
||||
))
|
||||
->setCaption(
|
||||
'You can temporarily disable Herald notifications when reparsing '.
|
||||
'a repository or importing a new repository.'));
|
||||
'You can temporarily disable Herald commit notifications when '.
|
||||
'reparsing a repository or importing a new repository.'));
|
||||
|
||||
$parsers = id(new PhutilSymbolLoader())
|
||||
->setAncestorClass('PhabricatorRepositoryCommitMessageDetailParser')
|
||||
|
@ -487,10 +595,12 @@ class PhabricatorRepositoryEditController
|
|||
->setCaption('Repository UUID from <tt>svn info</tt>.'));
|
||||
}
|
||||
|
||||
$form->appendChild('</div>');
|
||||
|
||||
$form
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->setValue('Save'));
|
||||
->setValue('Save Configuration'));
|
||||
|
||||
$panel = new AphrontPanelView();
|
||||
$panel->setHeader('Repository Tracking');
|
||||
|
|
|
@ -28,8 +28,8 @@ class PhabricatorRepositorySvnCommitDiscoveryDaemon
|
|||
}
|
||||
|
||||
$uri = $this->getBaseSVNLogURI();
|
||||
list($xml) = execx(
|
||||
'svn log --xml --non-interactive --quiet --limit 1 %s@HEAD',
|
||||
list($xml) = $repository->execxRemoteCommand(
|
||||
' log --xml --quiet --limit 1 %s@HEAD',
|
||||
$uri);
|
||||
|
||||
$results = $this->parseSVNLogXML($xml);
|
||||
|
@ -47,6 +47,7 @@ class PhabricatorRepositorySvnCommitDiscoveryDaemon
|
|||
|
||||
private function discoverCommit($commit, $epoch) {
|
||||
$uri = $this->getBaseSVNLogURI();
|
||||
$repository = $this->getRepository();
|
||||
|
||||
$discover = array(
|
||||
$commit => $epoch,
|
||||
|
@ -58,8 +59,8 @@ class PhabricatorRepositorySvnCommitDiscoveryDaemon
|
|||
// Find all the unknown commits on this path. Note that we permit
|
||||
// importing an SVN subdirectory rather than the entire repository, so
|
||||
// commits may be nonsequential.
|
||||
list($err, $xml, $stderr) = exec_manual(
|
||||
'svn log --xml --non-interactive --quiet --limit %d %s@%d',
|
||||
list($err, $xml, $stderr) = $repository->execRemoteCommand(
|
||||
' log --xml --quiet --limit %d %s@%d',
|
||||
$limit,
|
||||
$uri,
|
||||
$upper_bound - 1);
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
phutil_require_module('phabricator', 'applications/repository/constants/repositorytype');
|
||||
phutil_require_module('phabricator', 'applications/repository/daemon/commitdiscovery/base');
|
||||
|
||||
phutil_require_module('phutil', 'future/exec');
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
|
|
|
@ -32,6 +32,8 @@ class PhabricatorRepository extends PhabricatorRepositoryDAO {
|
|||
protected $versionControlSystem;
|
||||
protected $details = array();
|
||||
|
||||
private $sshKeyfile;
|
||||
|
||||
public function getConfiguration() {
|
||||
return array(
|
||||
self::CONFIG_AUX_PHID => true,
|
||||
|
@ -55,4 +57,240 @@ class PhabricatorRepository extends PhabricatorRepositoryDAO {
|
|||
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/storage/phid');
|
||||
phutil_require_module('phabricator', 'applications/repository/constants/repositorytype');
|
||||
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', 'xsprintf/csprintf');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorRepository.php');
|
||||
|
|
|
@ -68,8 +68,8 @@ abstract class PhabricatorRepositoryCommitParserWorker
|
|||
}
|
||||
|
||||
try {
|
||||
list($xml) = execx(
|
||||
"svn log --xml {$verbose} --limit 1 --non-interactive %s@%d",
|
||||
list($xml) = $this->repository->execxRemoteCommand(
|
||||
"log --xml {$verbose} --limit 1 %s@%d",
|
||||
$uri,
|
||||
$revision);
|
||||
} catch (CommandException $ex) {
|
||||
|
|
|
@ -496,11 +496,59 @@ class PhabricatorRepositorySvnCommitChangeParserWorker
|
|||
$commit_table = new PhabricatorRepositoryCommit();
|
||||
$commit_data = queryfx_all(
|
||||
$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(),
|
||||
$repository->getID(),
|
||||
$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(
|
||||
|
@ -545,10 +593,9 @@ class PhabricatorRepositorySvnCommitChangeParserWorker
|
|||
// position in the document.
|
||||
$all_paths = array_reverse(array_keys($parents));
|
||||
foreach (array_chunk($all_paths, 64) as $path_chunk) {
|
||||
list($raw_xml) = execx(
|
||||
'svn --non-interactive --xml ls %C',
|
||||
list($raw_xml) = $repository->execxRemoteCommand(
|
||||
'--xml ls %C',
|
||||
implode(' ', $path_chunk));
|
||||
|
||||
$xml = new SimpleXMLElement($raw_xml);
|
||||
foreach ($xml->list as $list) {
|
||||
$list_path = (string)$list['path'];
|
||||
|
@ -621,8 +668,8 @@ class PhabricatorRepositorySvnCommitChangeParserWorker
|
|||
$cache_loc = sys_get_temp_dir().'/diffusion.'.$hashkey.'.svnls';
|
||||
if (!Filesystem::pathExists($cache_loc)) {
|
||||
$tmp = new TempFile();
|
||||
execx(
|
||||
'svn --non-interactive --xml ls -R %s%s@%d > %s',
|
||||
$repository->execxRemoteCommand(
|
||||
'--xml ls -R %s%s@%d > %s',
|
||||
$repository->getDetail('remote-uri'),
|
||||
$path,
|
||||
$rev,
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
phutil_require_module('phabricator', 'applications/differential/constants/changetype');
|
||||
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/worker/commitchangeparser/base');
|
||||
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'));
|
||||
|
||||
// On RHEL6, doing a distro install of pcntl makes it available from the
|
||||
|
|
|
@ -209,7 +209,7 @@ class AphrontMySQLDatabaseConnection extends AphrontDatabaseConnection {
|
|||
$this->requireConnection();
|
||||
|
||||
// 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) {
|
||||
AphrontWriteGuard::willWrite();
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ final class AphrontFilePreviewView extends AphrontView {
|
|||
$link = phutil_render_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => $file->getViewURI(),
|
||||
'href' => $file->getBestURI(),
|
||||
'target' => '_blank',
|
||||
),
|
||||
$img);
|
||||
|
|
|
@ -250,7 +250,7 @@ function phabricator_shutdown() {
|
|||
return;
|
||||
}
|
||||
|
||||
if ($event['type'] != E_ERROR) {
|
||||
if ($event['type'] != E_ERROR && $event['type'] != E_PARSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -87,6 +87,18 @@
|
|||
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 {
|
||||
padding-top: 4px;
|
||||
font-size: 13px;
|
||||
|
|
|
@ -3,30 +3,5 @@
|
|||
*/
|
||||
|
||||
.phabricator-content-source-view {
|
||||
padding: 2px 20px 2px 0;
|
||||
font-size: 11px;
|
||||
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 {
|
||||
margin: 25px 0;
|
||||
max-width: 1118px;
|
||||
max-width: 1120px;
|
||||
border: 1px solid #666622;
|
||||
background: #efefdf;
|
||||
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/mobile.png (from phone.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