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

Rough in the new custom URI panel

Summary: Ref T10748. Ref T10366. No support for editing and no impact on the UI, but get some of the basics in place.

Test Plan: {F1223279}

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T10366, T10748

Differential Revision: https://secure.phabricator.com/D15742
This commit is contained in:
epriestley 2016-04-17 08:17:49 -07:00
parent 51838f990f
commit 92c50de8aa
5 changed files with 571 additions and 0 deletions

View file

@ -779,6 +779,7 @@ phutil_register_library_map(array(
'DiffusionRepositoryTag' => 'applications/diffusion/data/DiffusionRepositoryTag.php',
'DiffusionRepositoryTestAutomationController' => 'applications/diffusion/controller/DiffusionRepositoryTestAutomationController.php',
'DiffusionRepositoryURIsIndexEngineExtension' => 'applications/diffusion/engineextension/DiffusionRepositoryURIsIndexEngineExtension.php',
'DiffusionRepositoryURIsManagementPanel' => 'applications/diffusion/management/DiffusionRepositoryURIsManagementPanel.php',
'DiffusionRequest' => 'applications/diffusion/request/DiffusionRequest.php',
'DiffusionResolveRefsConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionResolveRefsConduitAPIMethod.php',
'DiffusionResolveUserQuery' => 'applications/diffusion/query/DiffusionResolveUserQuery.php',
@ -3216,6 +3217,7 @@ phutil_register_library_map(array(
'PhabricatorRepositoryTransaction' => 'applications/repository/storage/PhabricatorRepositoryTransaction.php',
'PhabricatorRepositoryTransactionQuery' => 'applications/repository/query/PhabricatorRepositoryTransactionQuery.php',
'PhabricatorRepositoryType' => 'applications/repository/constants/PhabricatorRepositoryType.php',
'PhabricatorRepositoryURI' => 'applications/repository/storage/PhabricatorRepositoryURI.php',
'PhabricatorRepositoryURIIndex' => 'applications/repository/storage/PhabricatorRepositoryURIIndex.php',
'PhabricatorRepositoryURINormalizer' => 'applications/repository/data/PhabricatorRepositoryURINormalizer.php',
'PhabricatorRepositoryURINormalizerTestCase' => 'applications/repository/data/__tests__/PhabricatorRepositoryURINormalizerTestCase.php',
@ -4978,6 +4980,7 @@ phutil_register_library_map(array(
'DiffusionRepositoryTag' => 'Phobject',
'DiffusionRepositoryTestAutomationController' => 'DiffusionRepositoryEditController',
'DiffusionRepositoryURIsIndexEngineExtension' => 'PhabricatorIndexEngineExtension',
'DiffusionRepositoryURIsManagementPanel' => 'DiffusionRepositoryManagementPanel',
'DiffusionRequest' => 'Phobject',
'DiffusionResolveRefsConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod',
'DiffusionResolveUserQuery' => 'Phobject',
@ -7875,6 +7878,7 @@ phutil_register_library_map(array(
'PhabricatorRepositoryTransaction' => 'PhabricatorApplicationTransaction',
'PhabricatorRepositoryTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'PhabricatorRepositoryType' => 'Phobject',
'PhabricatorRepositoryURI' => 'PhabricatorRepositoryDAO',
'PhabricatorRepositoryURIIndex' => 'PhabricatorRepositoryDAO',
'PhabricatorRepositoryURINormalizer' => 'Phobject',
'PhabricatorRepositoryURINormalizerTestCase' => 'PhabricatorTestCase',

View file

@ -0,0 +1,126 @@
<?php
final class DiffusionRepositoryURIsManagementPanel
extends DiffusionRepositoryManagementPanel {
const PANELKEY = 'uris';
public function getManagementPanelLabel() {
return pht('Clone / Fetch / Mirror');
}
public function getManagementPanelOrder() {
return 300;
}
public function buildManagementPanelContent() {
$repository = $this->getRepository();
$viewer = $this->getViewer();
$repository->attachURIs(array());
$uris = $repository->getURIs();
Javelin::initBehavior('phabricator-tooltips');
$rows = array();
foreach ($uris as $uri) {
$uri_name = $uri->getDisplayURI();
if ($uri->getIsDisabled()) {
$status_icon = 'fa-times grey';
} else {
$status_icon = 'fa-check green';
}
$uri_status = id(new PHUIIconView())->setIcon($status_icon);
switch ($uri->getEffectiveIOType()) {
case PhabricatorRepositoryURI::IO_OBSERVE:
$io_icon = 'fa-download green';
$io_label = pht('Observe');
break;
case PhabricatorRepositoryURI::IO_MIRROR:
$io_icon = 'fa-upload green';
$io_label = pht('Mirror');
break;
case PhabricatorRepositoryURI::IO_NONE:
$io_icon = 'fa-times grey';
$io_label = pht('No I/O');
break;
case PhabricatorRepositoryURI::IO_READ:
$io_icon = 'fa-folder blue';
$io_label = pht('Read Only');
break;
case PhabricatorRepositoryURI::IO_READWRITE:
$io_icon = 'fa-folder-open blue';
$io_label = pht('Read/Write');
break;
}
$uri_io = array(
id(new PHUIIconView())->setIcon($io_icon),
' ',
$io_label,
);
switch ($uri->getEffectiveDisplayType()) {
case PhabricatorRepositoryURI::DISPLAY_NEVER:
$display_icon = 'fa-eye-slash grey';
$display_label = pht('Hidden');
break;
case PhabricatorRepositoryURI::DISPLAY_ALWAYS:
$display_icon = 'fa-eye green';
$display_label = pht('Visible');
break;
}
$uri_display = array(
id(new PHUIIconView())->setIcon($display_icon),
' ',
$display_label,
);
$rows[] = array(
$uri_status,
$uri_name,
$uri_io,
$uri_display,
);
}
$table = id(new AphrontTableView($rows))
->setNoDataString(pht('This repository has no URIs.'))
->setHeaders(
array(
null,
pht('URI'),
pht('I/O'),
pht('Display'),
))
->setColumnClasses(
array(
null,
'pri wide',
null,
null,
));
$doc_href = PhabricatorEnv::getDoclink(
'Diffusion User Guide: Repository URIs');
$header = id(new PHUIHeaderView())
->setHeader(pht('Repository URIs'))
->addActionLink(
id(new PHUIButtonView())
->setIcon('fa-book')
->setHref($doc_href)
->setTag('a')
->setText(pht('Documentation')));
return id(new PHUIObjectBoxView())
->setHeader($header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setTable($table);
}
}

View file

@ -63,10 +63,12 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
private $commitCount = self::ATTACHABLE;
private $mostRecentCommit = self::ATTACHABLE;
private $projectPHIDs = self::ATTACHABLE;
private $uris = self::ATTACHABLE;
private $clusterWriteLock;
private $clusterWriteVersion;
public static function initializeNewRepository(PhabricatorUser $actor) {
$app = id(new PhabricatorApplicationQuery())
->setViewer($actor)
@ -2266,6 +2268,98 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
return $client;
}
/* -( Repository URIs )---------------------------------------------------- */
public function attachURIs(array $uris) {
$custom_map = array();
foreach ($uris as $key => $uri) {
$builtin_key = $uri->getRepositoryURIBuiltinKey();
if ($builtin_key !== null) {
$custom_map[$builtin_key] = $key;
}
}
$builtin_uris = $this->newBuiltinURIs();
$seen_builtins = array();
foreach ($builtin_uris as $builtin_uri) {
$builtin_key = $builtin_uri->getRepositoryURIBuiltinKey();
$seen_builtins[$builtin_key] = true;
// If this builtin URI is disabled, don't attach it and remove the
// persisted version if it exists.
if ($builtin_uri->getIsDisabled()) {
if (isset($custom_map[$builtin_key])) {
unset($uris[$custom_map[$builtin_key]]);
}
continue;
}
// If we don't have a persisted version of the URI, add the builtin
// version.
if (empty($custom_map[$builtin_key])) {
$uris[] = $builtin_uri;
}
}
// Remove any builtins which no longer exist.
foreach ($custom_map as $builtin_key => $key) {
if (empty($seen_builtins[$builtin_key])) {
unset($uris[$key]);
}
}
$this->uris = $uris;
return $this;
}
public function getURIs() {
return $this->assertAttached($this->uris);
}
protected function newBuiltinURIs() {
$has_callsign = ($this->getCallsign() !== null);
$has_shortname = ($this->getRepositorySlug() !== null);
$identifier_map = array(
PhabricatorRepositoryURI::BUILTIN_IDENTIFIER_CALLSIGN => $has_callsign,
PhabricatorRepositoryURI::BUILTIN_IDENTIFIER_SHORTNAME => $has_shortname,
PhabricatorRepositoryURI::BUILTIN_IDENTIFIER_ID => true,
);
$allow_http = PhabricatorEnv::getEnvConfig('diffusion.allow-http-auth');
$base_uri = PhabricatorEnv::getURI('/');
$base_uri = new PhutilURI($base_uri);
$has_https = ($base_uri->getProtocol() == 'https');
$has_https = ($has_https && $allow_http);
$has_http = !PhabricatorEnv::getEnvConfig('security.require-https');
$has_http = ($has_http && $allow_http);
// TODO: Maybe allow users to disable this by default somehow?
$has_ssh = true;
$protocol_map = array(
PhabricatorRepositoryURI::BUILTIN_PROTOCOL_SSH => $has_ssh,
PhabricatorRepositoryURI::BUILTIN_PROTOCOL_HTTPS => $has_https,
PhabricatorRepositoryURI::BUILTIN_PROTOCOL_HTTP => $has_http,
);
$uris = array();
foreach ($protocol_map as $protocol => $proto_supported) {
foreach ($identifier_map as $identifier => $id_supported) {
$uris[] = PhabricatorRepositoryURI::initializeNewURI($this)
->setBuiltinProtocol($protocol)
->setBuiltinIdentifier($identifier)
->setIsDisabled(!$proto_supported || !$id_supported);
}
}
return $uris;
}
/* -( Cluster Synchronization )-------------------------------------------- */

View file

@ -0,0 +1,300 @@
<?php
final class PhabricatorRepositoryURI
extends PhabricatorRepositoryDAO {
protected $repositoryPHID;
protected $uri;
protected $builtinProtocol;
protected $builtinIdentifier;
protected $credentialPHID;
protected $ioType;
protected $displayType;
protected $isDisabled;
private $repository = self::ATTACHABLE;
const BUILTIN_PROTOCOL_SSH = 'ssh';
const BUILTIN_PROTOCOL_HTTP = 'http';
const BUILTIN_PROTOCOL_HTTPS = 'https';
const BUILTIN_IDENTIFIER_ID = 'id';
const BUILTIN_IDENTIFIER_SHORTNAME = 'shortname';
const BUILTIN_IDENTIFIER_CALLSIGN = 'callsign';
const DISPLAY_DEFAULT = 'default';
const DISPLAY_NEVER = 'never';
const DISPLAY_ALWAYS = 'always';
const IO_DEFAULT = 'default';
const IO_OBSERVE = 'observe';
const IO_MIRROR = 'mirror';
const IO_NONE = 'none';
const IO_READ = 'read';
const IO_READWRITE = 'readwrite';
protected function getConfiguration() {
return array(
self::CONFIG_AUX_PHID => true,
self::CONFIG_COLUMN_SCHEMA => array(
'uri' => 'text',
'builtinProtocol' => 'text32?',
'builtinIdentifier' => 'text32?',
'ioType' => 'text32',
'displayType' => 'text32',
'isDisabled' => 'bool',
),
self::CONFIG_KEY_SCHEMA => array(
'key_builtin' => array(
'columns' => array(
'repositoryPHID',
'builtinProtocol',
'builtinIdentifier',
),
'unique' => true,
),
),
) + parent::getConfiguration();
}
public static function initializeNewURI(PhabricatorRepository $repository) {
return id(new self())
->attachRepository($repository)
->setRepositoryPHID($repository->getPHID())
->setIoType(self::IO_DEFAULT)
->setDisplayType(self::DISPLAY_DEFAULT)
->setIsDisabled(0);
}
public function attachRepository(PhabricatorRepository $repository) {
$this->repository = $repository;
return $this;
}
public function getRepository() {
return $this->assertAttached($this->repository);
}
public function getRepositoryURIBuiltinKey() {
if (!$this->getBuiltinProtocol()) {
return null;
}
$parts = array(
$this->getBuiltinProtocol(),
$this->getBuiltinIdentifier(),
);
return implode('.', $parts);
}
public function isBuiltin() {
return (bool)$this->getBuiltinProtocol();
}
public function getEffectiveDisplayType() {
$display = $this->getDisplayType();
if ($display != self::IO_DEFAULT) {
return $display;
}
switch ($this->getEffectiveIOType()) {
case self::IO_MIRROR:
case self::IO_OBSERVE:
return self::DISPLAY_NEVER;
case self::IO_NONE:
if ($this->isBuiltin()) {
return self::DISPLAY_NEVER;
} else {
return self::DISPLAY_ALWAYS;
}
case self::IO_READ:
case self::IO_READWRITE:
// By default, only show the "best" version of the builtin URI, not the
// other redundant versions.
if ($this->isBuiltin()) {
$repository = $this->getRepository();
$other_uris = $repository->getURIs();
$identifier_value = array(
self::BUILTIN_IDENTIFIER_CALLSIGN => 3,
self::BUILTIN_IDENTIFIER_SHORTNAME => 2,
self::BUILTIN_IDENTIFIER_ID => 1,
);
$have_identifiers = array();
foreach ($other_uris as $other_uri) {
if ($other_uri->getIsDisabled()) {
continue;
}
$identifier = $other_uri->getBuiltinIdentifier();
if (!$identifier) {
continue;
}
$have_identifiers[$identifier] = $identifier_value[$identifier];
}
$best_identifier = max($have_identifiers);
$this_identifier = $identifier_value[$this->getBuiltinIdentifier()];
if ($this_identifier < $best_identifier) {
return self::DISPLAY_NEVER;
}
}
return self::DISPLAY_ALWAYS;
}
}
public function getEffectiveIOType() {
$io = $this->getIoType();
if ($io != self::IO_DEFAULT) {
return $io;
}
if ($this->isBuiltin()) {
$repository = $this->getRepository();
$other_uris = $repository->getURIs();
$any_observe = false;
foreach ($other_uris as $other_uri) {
if ($other_uri->getIoType() == self::IO_OBSERVE) {
$any_observe = true;
break;
}
}
if ($any_observe) {
return self::IO_READ;
} else {
return self::IO_READWRITE;
}
}
return self::IO_IGNORE;
}
public function getDisplayURI() {
$uri = new PhutilURI($this->getURI());
$protocol = $this->getForcedProtocol();
if ($protocol) {
$uri->setProtocol($protocol);
}
$user = $this->getForcedUser();
if ($user) {
$uri->setUser($user);
}
$host = $this->getForcedHost();
if ($host) {
$uri->setDomain($host);
}
$port = $this->getForcedPort();
if ($port) {
$uri->setPort($port);
}
$path = $this->getForcedPath();
if ($path) {
$uri->setPath($path);
}
return $uri;
}
private function getForcedProtocol() {
switch ($this->getBuiltinProtocol()) {
case self::BUILTIN_PROTOCOL_SSH:
return 'ssh';
case self::BUILTIN_PROTOCOL_HTTP:
return 'http';
case self::BUILTIN_PROTOCOL_HTTPS:
return 'https';
default:
return null;
}
}
private function getForcedUser() {
switch ($this->getBuiltinProtocol()) {
case self::BUILTIN_PROTOCOL_SSH:
return PhabricatorEnv::getEnvConfig('diffusion.ssh-user');
default:
return null;
}
}
private function getForcedHost() {
$phabricator_uri = PhabricatorEnv::getURI('/');
$phabricator_uri = new PhutilURI($phabricator_uri);
$phabricator_host = $phabricator_uri->getDomain();
switch ($this->getBuiltinProtocol()) {
case self::BUILTIN_PROTOCOL_SSH:
$ssh_host = PhabricatorEnv::getEnvConfig('diffusion.ssh-host');
if ($ssh_host !== null) {
return $ssh_host;
}
return $phabricator_host;
case self::BUILTIN_PROTOCOL_HTTP:
case self::BUILTIN_PROTOCOL_HTTPS:
return $phabricator_host;
default:
return null;
}
}
private function getForcedPort() {
switch ($this->getBuiltinProtocol()) {
case self::BUILTIN_PROTOCOL_SSH:
return PhabricatorEnv::getEnvConfig('diffusion.ssh-port');
case self::BUILTIN_PROTOCOL_HTTP:
case self::BUILTIN_PROTOCOL_HTTPS:
default:
return null;
}
}
private function getForcedPath() {
if (!$this->isBuiltin()) {
return null;
}
$repository = $this->getRepository();
$id = $repository->getID();
$callsign = $repository->getCallsign();
$short_name = $repository->getRepositorySlug();
$clone_name = $repository->getCloneName();
if ($repository->isGit()) {
$suffix = '.git';
} else if ($repository->isHg()) {
$suffix = '/';
} else {
$suffix = '';
}
switch ($this->getBuiltinIdentifier()) {
case self::BUILTIN_IDENTIFIER_ID:
return "/diffusion/{$id}/{$clone_name}{$suffix}";
case self::BUILTIN_IDENTIFIER_SHORTNAME:
return "/source/{$short_name}{$suffix}";
case self::BUILTIN_IDENTIFIER_CALLSIGN:
return "/diffusion/{$callsign}/{$clone_name}{$suffix}";
default:
return null;
}
}
}

View file

@ -0,0 +1,47 @@
@title Diffusion User Guide: URIs
@group userguide
Guide to configuring repository URIs for fetching, cloning and mirroring.
Overview
========
WARNING: This document describes a feature which is still under development,
and is not necessarily accurate or complete.
Phabricator can host, observe, mirror, and proxy repositories. For example,
here are some supported use cases:
**Host Repositories**: Phabricator can host repositories locally. Phabricator
maintains the writable master version of the repository, and you can push and
pull the repository. This is the most straightforward kind of repository
configuration, and similar to repositories on other services like GitHub or
Bitbucket.
**Observe Repositories**: Phabricator can create a copy of an repository which
is hosted elsewhere (like GitHub or Bitbucket) and track updates to the remote
repository. This will create a read-only copy of the repository in Phabricator.
**Mirror Repositories**: Phabricator can publish any repository to mirrors,
updating the mirrors as changes are made to the repository. This works with
both local hosted repositories and remote repositories that Phabricator is
observing.
**Proxy Repositories**: If you are observing a repository, you can allow users
to read Phabricator's copy of the repository. Phabricator supports granular
read permissions, so this can let you open a private repository up a little
bit in a flexible way.
**Import Repositories**: If you have a repository elsewhere that you want to
host on Phabricator, you can observe the remote repository first, then turn
the tracking off once the repository fully synchronizes. This allows you to
copy an existing repository and begin hosting it in Phabricator.
You can also import repositories by creating an empty hosted repository and
then pushing everything to the repository directly.
You configure the behavior of a Phabricator repository by adding and
configuring URIs and marking them to be fetched from, mirrored to, clonable,
and so on. By configuring all the URIs that a repository should interact with
and expose to users, you configure the read, write, and mirroring behavior
of the repository.