1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-23 22:10:55 +01:00

Merge branch 'master' of github.com:facebook/phabricator into unit_status

This commit is contained in:
mgummelt 2011-09-08 18:24:54 -07:00
commit 7f601a78d3
46 changed files with 1006 additions and 182 deletions

View 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;

View 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");
}

View file

@ -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',

View file

@ -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',

View file

@ -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;

View file

@ -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/');
} }

View file

@ -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,

View file

@ -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(

View file

@ -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');

View file

@ -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('');
} }

View file

@ -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:

View file

@ -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;

View file

@ -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!");
} }

View file

@ -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');

View file

@ -44,6 +44,21 @@ class DiffusionCommitController extends DiffusionController {
$commit_data = $drequest->loadCommitData(); $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(); $engine = PhabricatorMarkupEngine::newDifferentialMarkupEngine();
require_celerity_resource('diffusion-commit-view-css'); require_celerity_resource('diffusion-commit-view-css');
@ -69,6 +84,7 @@ class DiffusionCommitController extends DiffusionController {
'</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,7 +163,6 @@ class DiffusionCommitController extends DiffusionController {
$content[] = $change_panel; $content[] = $change_panel;
if ($changes) {
$changesets = DiffusionPathChange::convertToDifferentialChangesets( $changesets = DiffusionPathChange::convertToDifferentialChangesets(
$changes); $changes);
@ -176,13 +208,6 @@ class DiffusionCommitController extends DiffusionController {
'<div class="differential-primary-pane">'. '<div class="differential-primary-pane">'.
$change_list->render(). $change_list->render().
'</div>'; '</div>';
} else {
$change_list =
'<div style="margin: 2em; color: #666; padding: 1em;
background: #eee;">'.
'(no changes blah blah)'.
'</div>';
}
$content[] = $change_list; $content[] = $change_list;
} }

View file

@ -30,6 +30,7 @@ abstract class DiffusionBrowseQuery {
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>

View file

@ -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);

View file

@ -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);
} }

View file

@ -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');

View file

@ -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,

View file

@ -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');

View file

@ -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, '/');

View file

@ -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();

View file

@ -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}");
} }
} }

View file

@ -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;

View file

@ -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');

View file

@ -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,
));
}
}

View file

@ -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');

View file

@ -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),

View file

@ -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');

View file

@ -28,8 +28,8 @@ 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);
@ -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);

View file

@ -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');

View file

@ -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');
}
} }

View file

@ -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');

View file

@ -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) {

View file

@ -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,

View file

@ -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');

View file

@ -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

View file

@ -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();
} }

View file

@ -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);

View file

@ -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;
} }

View file

@ -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;

View file

@ -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);
} }

View file

@ -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;

View file

@ -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)

Binary file not shown.

After

Width:  |  Height:  |  Size: 600 B