mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-18 19:40:55 +01:00
Merge branch 'master' into redesign-2015
This commit is contained in:
commit
7d7e13d79b
50 changed files with 727 additions and 313 deletions
|
@ -8,7 +8,7 @@
|
|||
return array(
|
||||
'names' => array(
|
||||
'core.pkg.css' => '9cbee819',
|
||||
'core.pkg.js' => '41f5edc5',
|
||||
'core.pkg.js' => 'f1e8abd7',
|
||||
'darkconsole.pkg.js' => 'e7393ebb',
|
||||
'differential.pkg.css' => 'fe951924',
|
||||
'differential.pkg.js' => 'ebef29b1',
|
||||
|
@ -459,7 +459,7 @@ return array(
|
|||
'rsrc/js/core/behavior-object-selector.js' => '49b73b36',
|
||||
'rsrc/js/core/behavior-oncopy.js' => '2926fff2',
|
||||
'rsrc/js/core/behavior-phabricator-nav.js' => '56a1ca03',
|
||||
'rsrc/js/core/behavior-phabricator-remarkup-assist.js' => '095ed313',
|
||||
'rsrc/js/core/behavior-phabricator-remarkup-assist.js' => 'eeaa9e5a',
|
||||
'rsrc/js/core/behavior-refresh-csrf.js' => '7814b593',
|
||||
'rsrc/js/core/behavior-remarkup-preview.js' => 'f7379f45',
|
||||
'rsrc/js/core/behavior-reorder-applications.js' => '76b9fc3e',
|
||||
|
@ -609,7 +609,7 @@ return array(
|
|||
'javelin-behavior-phabricator-notification-example' => '8ce821c5',
|
||||
'javelin-behavior-phabricator-object-selector' => '49b73b36',
|
||||
'javelin-behavior-phabricator-oncopy' => '2926fff2',
|
||||
'javelin-behavior-phabricator-remarkup-assist' => '095ed313',
|
||||
'javelin-behavior-phabricator-remarkup-assist' => 'eeaa9e5a',
|
||||
'javelin-behavior-phabricator-reveal-content' => '60821bc7',
|
||||
'javelin-behavior-phabricator-search-typeahead' => '048330fa',
|
||||
'javelin-behavior-phabricator-show-older-transactions' => 'dbbf48b6',
|
||||
|
@ -896,15 +896,6 @@ return array(
|
|||
'javelin-stratcom',
|
||||
'javelin-vector',
|
||||
),
|
||||
'095ed313' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
'javelin-dom',
|
||||
'phabricator-phtize',
|
||||
'phabricator-textareautils',
|
||||
'javelin-workflow',
|
||||
'javelin-vector',
|
||||
),
|
||||
'0a3f3021' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
|
@ -1951,6 +1942,15 @@ return array(
|
|||
'phabricator-phtize',
|
||||
'javelin-dom',
|
||||
),
|
||||
'eeaa9e5a' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
'javelin-dom',
|
||||
'phabricator-phtize',
|
||||
'phabricator-textareautils',
|
||||
'javelin-workflow',
|
||||
'javelin-vector',
|
||||
),
|
||||
'efe49472' => array(
|
||||
'javelin-install',
|
||||
'javelin-util',
|
||||
|
|
5
resources/sql/autopatches/20150616.divinerrepository.sql
Normal file
5
resources/sql/autopatches/20150616.divinerrepository.sql
Normal file
|
@ -0,0 +1,5 @@
|
|||
ALTER TABLE {$NAMESPACE}_diviner.diviner_livebook
|
||||
ADD COLUMN repositoryPHID VARBINARY(64) AFTER name;
|
||||
|
||||
ALTER TABLE {$NAMESPACE}_diviner.diviner_livesymbol
|
||||
ADD COLUMN repositoryPHID VARBINARY(64) AFTER bookPHID;
|
|
@ -3288,7 +3288,6 @@ phutil_register_library_map(array(
|
|||
'phabricator_format_local_time' => 'view/viewutils.php',
|
||||
'phabricator_relative_date' => 'view/viewutils.php',
|
||||
'phabricator_time' => 'view/viewutils.php',
|
||||
'phabricator_time_format' => 'view/viewutils.php',
|
||||
'phid_get_subtype' => 'applications/phid/utils.php',
|
||||
'phid_get_type' => 'applications/phid/utils.php',
|
||||
'phid_group_by_type' => 'applications/phid/utils.php',
|
||||
|
|
|
@ -35,8 +35,10 @@ abstract class AphrontController extends Phobject {
|
|||
|
||||
throw new PhutilMethodNotImplementedException(
|
||||
pht(
|
||||
'Controllers must implement either handleRequest() (recommended) '.
|
||||
'or processRequest() (deprecated).'));
|
||||
'Controllers must implement either %s (recommended) '.
|
||||
'or %s (deprecated).',
|
||||
'handleRequest()',
|
||||
'processRequest()'));
|
||||
}
|
||||
|
||||
final public function setRequest(AphrontRequest $request) {
|
||||
|
@ -46,7 +48,7 @@ abstract class AphrontController extends Phobject {
|
|||
|
||||
final public function getRequest() {
|
||||
if (!$this->request) {
|
||||
throw new Exception(pht('Call setRequest() before getRequest()!'));
|
||||
throw new PhutilInvalidStateException('setRequest');
|
||||
}
|
||||
return $this->request;
|
||||
}
|
||||
|
@ -81,10 +83,12 @@ abstract class AphrontController extends Phobject {
|
|||
}
|
||||
|
||||
public function getDefaultResourceSource() {
|
||||
throw new Exception(
|
||||
throw new PhutilMethodNotImplementedException(
|
||||
pht(
|
||||
'A Controller must implement getDefaultResourceSource() before you '.
|
||||
'can invoke requireResource() or initBehavior().'));
|
||||
'A Controller must implement %s before you can invoke %s or %s.',
|
||||
'getDefaultResourceSource()',
|
||||
'requireResource()',
|
||||
'initBehavior()'));
|
||||
}
|
||||
|
||||
public function requireResource($symbol) {
|
||||
|
|
|
@ -18,7 +18,7 @@ final class PhabricatorAuthInviteEngine extends Phobject {
|
|||
|
||||
public function getViewer() {
|
||||
if (!$this->viewer) {
|
||||
throw new Exception(pht('Call setViewer() before getViewer()!'));
|
||||
throw new PhutilInvalidStateException('setViewer');
|
||||
}
|
||||
return $this->viewer;
|
||||
}
|
||||
|
|
|
@ -437,10 +437,11 @@ final class PhabricatorCalendarEventEditController
|
|||
->setValue($end_disabled);
|
||||
}
|
||||
|
||||
$description = id(new AphrontFormTextAreaControl())
|
||||
$description = id(new PhabricatorRemarkupControl())
|
||||
->setLabel(pht('Description'))
|
||||
->setName('description')
|
||||
->setValue($description);
|
||||
->setValue($description)
|
||||
->setUser($viewer);
|
||||
|
||||
$view_policies = id(new AphrontFormPolicyControl())
|
||||
->setUser($viewer)
|
||||
|
|
|
@ -362,10 +362,19 @@ final class PhabricatorCalendarEventViewController
|
|||
pht('Icon'),
|
||||
$icon_display);
|
||||
|
||||
$properties->addSectionHeader(
|
||||
pht('Description'),
|
||||
PHUIPropertyListView::ICON_SUMMARY);
|
||||
$properties->addTextContent($event->getDescription());
|
||||
if (strlen($event->getDescription())) {
|
||||
|
||||
$description = PhabricatorMarkupEngine::renderOneObject(
|
||||
id(new PhabricatorMarkupOneOff())->setContent($event->getDescription()),
|
||||
'default',
|
||||
$viewer);
|
||||
|
||||
$properties->addSectionHeader(
|
||||
pht('Description'),
|
||||
PHUIPropertyListView::ICON_SUMMARY);
|
||||
|
||||
$properties->addTextContent($description);
|
||||
}
|
||||
|
||||
return $properties;
|
||||
}
|
||||
|
|
|
@ -126,15 +126,15 @@ final class PhabricatorCalendarEventSearchEngine
|
|||
$query->withDateRange($min_range, $max_range);
|
||||
}
|
||||
|
||||
$invited_phids = $saved->getParameter('invitedPHIDs');
|
||||
$invited_phids = $saved->getParameter('invitedPHIDs', array());
|
||||
$invited_phids = $user_datasource->evaluateTokens($invited_phids);
|
||||
if ($invited_phids) {
|
||||
$invited_phids = $user_datasource->evaluateTokens($invited_phids);
|
||||
$query->withInvitedPHIDs($invited_phids);
|
||||
}
|
||||
|
||||
$creator_phids = $saved->getParameter('creatorPHIDs');
|
||||
$creator_phids = $saved->getParameter('creatorPHIDs', array());
|
||||
$creator_phids = $user_datasource->evaluateTokens($creator_phids);
|
||||
if ($creator_phids) {
|
||||
$creator_phids = $user_datasource->evaluateTokens($creator_phids);
|
||||
$query->withCreatorPHIDs($creator_phids);
|
||||
}
|
||||
|
||||
|
@ -313,17 +313,31 @@ final class PhabricatorCalendarEventSearchEngine
|
|||
$list = new PHUIObjectItemListView();
|
||||
foreach ($events as $event) {
|
||||
$from = phabricator_datetime($event->getDateFrom(), $viewer);
|
||||
$to = phabricator_datetime($event->getDateTo(), $viewer);
|
||||
$duration = '';
|
||||
$creator_handle = $handles[$event->getUserPHID()];
|
||||
|
||||
$attendees = array();
|
||||
foreach ($event->getInvitees() as $invitee) {
|
||||
$attendees[] = $invitee->getInviteePHID();
|
||||
}
|
||||
|
||||
$attendees = pht(
|
||||
'Attending: %s',
|
||||
$viewer->renderHandleList($attendees)
|
||||
->setAsInline(1)
|
||||
->render());
|
||||
|
||||
if (strlen($event->getDuration()) > 0) {
|
||||
$duration = pht(
|
||||
'Duration: %s',
|
||||
$event->getDuration());
|
||||
}
|
||||
|
||||
$item = id(new PHUIObjectItemView())
|
||||
->setHeader($event->getName())
|
||||
->setHref($event->getURI())
|
||||
->addByline(pht('Creator: %s', $creator_handle->renderLink()))
|
||||
->addAttribute(pht('From %s to %s', $from, $to))
|
||||
->addAttribute(id(new PhutilUTF8StringTruncator())
|
||||
->setMaximumGlyphs(64)
|
||||
->truncateString($event->getDescription()));
|
||||
->setHeader($viewer->renderHandle($event->getPHID())->render())
|
||||
->addAttribute($attendees)
|
||||
->addIcon('none', $from)
|
||||
->addIcon('none', $duration);
|
||||
|
||||
$list->addItem($item);
|
||||
}
|
||||
|
|
|
@ -373,6 +373,29 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
|
|||
return false;
|
||||
}
|
||||
|
||||
public function getDuration() {
|
||||
$seconds = $this->dateTo - $this->dateFrom;
|
||||
$minutes = round($seconds / 60, 1);
|
||||
$hours = round($minutes / 60, 3);
|
||||
$days = round($hours / 24, 2);
|
||||
|
||||
$duration = '';
|
||||
|
||||
if ($days >= 1) {
|
||||
return pht(
|
||||
'%s day(s)',
|
||||
round($days, 1));
|
||||
} else if ($hours >= 1) {
|
||||
return pht(
|
||||
'%s hour(s)',
|
||||
round($hours, 1));
|
||||
} else if ($minutes >= 1) {
|
||||
return pht(
|
||||
'%s minute(s)',
|
||||
round($minutes, 0));
|
||||
}
|
||||
}
|
||||
|
||||
/* -( Markup Interface )--------------------------------------------------- */
|
||||
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ abstract class ConduitAPIMethod
|
|||
|
||||
$query = $this->newQueryObject();
|
||||
if ($query) {
|
||||
$types['order'] = 'order';
|
||||
$types['order'] = 'optional order';
|
||||
$types += $this->getPagerParamTypes();
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@ final class PhabricatorSyntaxHighlightingConfigOptions
|
|||
}
|
||||
|
||||
public function getOptions() {
|
||||
|
||||
$caches_href = PhabricatorEnv::getDocLink('Managing Caches');
|
||||
|
||||
return array(
|
||||
|
@ -74,31 +73,43 @@ final class PhabricatorSyntaxHighlightingConfigOptions
|
|||
'c' => 'C',
|
||||
'coffee-script' => 'CoffeeScript',
|
||||
'cpp' => 'C++',
|
||||
'csharp' => 'C#',
|
||||
'css' => 'CSS',
|
||||
'd' => 'D',
|
||||
'diff' => 'Diff',
|
||||
'django' => 'Django Templating',
|
||||
'docker' => 'Docker',
|
||||
'erb' => 'Embedded Ruby/ERB',
|
||||
'erlang' => 'Erlang',
|
||||
'go' => 'Golang',
|
||||
'groovy' => 'Groovy',
|
||||
'haskell' => 'Haskell',
|
||||
'html' => 'HTML',
|
||||
'http' => 'HTTP',
|
||||
'invisible' => 'Invisible',
|
||||
'java' => 'Java',
|
||||
'js' => 'Javascript',
|
||||
'json' => 'JSON',
|
||||
'make' => 'Makefile',
|
||||
'mysql' => 'MySQL',
|
||||
'nginx' => 'Nginx Configuration',
|
||||
'objc' => 'Objective-C',
|
||||
'perl' => 'Perl',
|
||||
'php' => 'PHP',
|
||||
'postgresql' => 'PostgreSQL',
|
||||
'pot' => 'Gettext Catalog',
|
||||
'puppet' => 'Puppet',
|
||||
'rest' => 'reStructuredText',
|
||||
'text' => 'Plain Text',
|
||||
'python' => 'Python',
|
||||
'rainbow' => 'Rainbow',
|
||||
'remarkup' => 'Remarkup',
|
||||
'rest' => 'reStructuredText',
|
||||
'robotframework' => 'RobotFramework',
|
||||
'rst' => 'reStructuredText',
|
||||
'ruby' => 'Ruby',
|
||||
'sql' => 'SQL',
|
||||
'tex' => 'LaTeX',
|
||||
'text' => 'Plain Text',
|
||||
'twig' => 'Twig',
|
||||
'xml' => 'XML',
|
||||
'yaml' => 'YAML',
|
||||
))
|
||||
|
|
|
@ -64,7 +64,7 @@ final class ConpherenceTransactionView extends AphrontView {
|
|||
public function render() {
|
||||
$viewer = $this->getUser();
|
||||
if (!$viewer) {
|
||||
throw new Exception(pht('Call setUser() before render()!'));
|
||||
throw new PhutilInvalidStateException('setUser');
|
||||
}
|
||||
|
||||
require_celerity_resource('conpherence-transaction-css');
|
||||
|
|
|
@ -127,6 +127,13 @@ final class DarkConsoleCore extends Phobject {
|
|||
}
|
||||
return $data;
|
||||
} else {
|
||||
// Truncate huge strings. Since the data doesn't really matter much,
|
||||
// just truncate bytes to avoid PhutilUTF8StringTruncator overhead.
|
||||
$length = strlen($data);
|
||||
$max = 4096;
|
||||
if ($length > $max) {
|
||||
$data = substr($data, 0, $max).'...<'.$length.' bytes>...';
|
||||
}
|
||||
return phutil_utf8ize($data);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -283,9 +283,7 @@ final class PhabricatorDashboardPanelRenderingEngine extends Phobject {
|
|||
*/
|
||||
private function detectRenderingCycle(PhabricatorDashboardPanel $panel) {
|
||||
if ($this->parentPanelPHIDs === null) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'You must call setParentPanelPHIDs() before rendering panels.'));
|
||||
throw new PhutilInvalidStateException('setParentPanelPHIDs');
|
||||
}
|
||||
|
||||
$max_depth = 4;
|
||||
|
|
|
@ -20,6 +20,8 @@ final class DiffusionFileContentQueryConduitAPIMethod
|
|||
'path' => 'required string',
|
||||
'commit' => 'required string',
|
||||
'needsBlame' => 'optional bool',
|
||||
'timeout' => 'optional int',
|
||||
'byteLimit' => 'optional int',
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -31,16 +33,30 @@ final class DiffusionFileContentQueryConduitAPIMethod
|
|||
$file_query
|
||||
->setViewer($request->getUser())
|
||||
->setNeedsBlame($needs_blame);
|
||||
|
||||
$timeout = $request->getValue('timeout');
|
||||
if ($timeout) {
|
||||
$file_query->setTimeout($timeout);
|
||||
}
|
||||
|
||||
$byte_limit = $request->getValue('byteLimit');
|
||||
if ($byte_limit) {
|
||||
$file_query->setByteLimit($byte_limit);
|
||||
}
|
||||
|
||||
$file_content = $file_query->loadFileContent();
|
||||
|
||||
if ($needs_blame) {
|
||||
list($text_list, $rev_list, $blame_dict) = $file_query->getBlameData();
|
||||
} else {
|
||||
$text_list = $rev_list = $blame_dict = array();
|
||||
}
|
||||
|
||||
$file_content
|
||||
->setBlameDict($blame_dict)
|
||||
->setRevList($rev_list)
|
||||
->setTextList($text_list);
|
||||
|
||||
return $file_content->toDictionary();
|
||||
}
|
||||
|
||||
|
|
|
@ -54,14 +54,27 @@ final class DiffusionBrowseFileController extends DiffusionBrowseController {
|
|||
$needs_blame = ($show_blame && !$show_color) ||
|
||||
($show_blame && $request->isAjax());
|
||||
|
||||
$params = array(
|
||||
'commit' => $drequest->getCommit(),
|
||||
'path' => $drequest->getPath(),
|
||||
'needsBlame' => $needs_blame,
|
||||
);
|
||||
|
||||
$byte_limit = null;
|
||||
if ($view !== 'raw') {
|
||||
$byte_limit = PhabricatorFileStorageEngine::getChunkThreshold();
|
||||
$time_limit = 10;
|
||||
|
||||
$params += array(
|
||||
'timeout' => $time_limit,
|
||||
'byteLimit' => $byte_limit,
|
||||
);
|
||||
}
|
||||
|
||||
$file_content = DiffusionFileContent::newFromConduit(
|
||||
$this->callConduitWithDiffusionRequest(
|
||||
'diffusion.filecontentquery',
|
||||
array(
|
||||
'commit' => $drequest->getCommit(),
|
||||
'path' => $drequest->getPath(),
|
||||
'needsBlame' => $needs_blame,
|
||||
)));
|
||||
$params));
|
||||
$data = $file_content->getCorpus();
|
||||
|
||||
if ($view === 'raw') {
|
||||
|
@ -71,8 +84,13 @@ final class DiffusionBrowseFileController extends DiffusionBrowseController {
|
|||
$this->loadLintMessages();
|
||||
$this->coverage = $drequest->loadCoverage();
|
||||
|
||||
$binary_uri = null;
|
||||
if (ArcanistDiffUtils::isHeuristicBinaryFile($data)) {
|
||||
if ($byte_limit && (strlen($data) == $byte_limit)) {
|
||||
$corpus = $this->buildErrorCorpus(
|
||||
pht(
|
||||
'This file is larger than %s byte(s), and too large to display '.
|
||||
'in the web UI.',
|
||||
$byte_limit));
|
||||
} else if (ArcanistDiffUtils::isHeuristicBinaryFile($data)) {
|
||||
$file = $this->loadFileForData($path, $data);
|
||||
$file_uri = $file->getBestURI();
|
||||
|
||||
|
@ -80,7 +98,6 @@ final class DiffusionBrowseFileController extends DiffusionBrowseController {
|
|||
$corpus = $this->buildImageCorpus($file_uri);
|
||||
} else {
|
||||
$corpus = $this->buildBinaryCorpus($file_uri, $data);
|
||||
$binary_uri = $file_uri;
|
||||
}
|
||||
} else {
|
||||
// Build the content of the file.
|
||||
|
@ -940,6 +957,21 @@ final class DiffusionBrowseFileController extends DiffusionBrowseController {
|
|||
return $box;
|
||||
}
|
||||
|
||||
private function buildErrorCorpus($message) {
|
||||
$text = id(new PHUIBoxView())
|
||||
->addPadding(PHUI::PADDING_LARGE)
|
||||
->appendChild($message);
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader(pht('Details'));
|
||||
|
||||
$box = id(new PHUIObjectBoxView())
|
||||
->setHeader($header)
|
||||
->appendChild($text);
|
||||
|
||||
return $box;
|
||||
}
|
||||
|
||||
private function buildBeforeResponse($before) {
|
||||
$request = $this->getRequest();
|
||||
$drequest = $this->getDiffusionRequest();
|
||||
|
|
|
@ -11,6 +11,26 @@ abstract class DiffusionFileContentQuery extends DiffusionQuery {
|
|||
private $needsBlame;
|
||||
private $fileContent;
|
||||
private $viewer;
|
||||
private $timeout;
|
||||
private $byteLimit;
|
||||
|
||||
public function setTimeout($timeout) {
|
||||
$this->timeout = $timeout;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTimeout() {
|
||||
return $this->timeout;
|
||||
}
|
||||
|
||||
public function setByteLimit($byte_limit) {
|
||||
$this->byteLimit = $byte_limit;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getByteLimit() {
|
||||
return $this->byteLimit;
|
||||
}
|
||||
|
||||
final public static function newFromDiffusionRequest(
|
||||
DiffusionRequest $request) {
|
||||
|
@ -21,7 +41,31 @@ abstract class DiffusionFileContentQuery extends DiffusionQuery {
|
|||
abstract protected function executeQueryFromFuture(Future $future);
|
||||
|
||||
final public function loadFileContentFromFuture(Future $future) {
|
||||
$this->fileContent = $this->executeQueryFromFuture($future);
|
||||
|
||||
if ($this->timeout) {
|
||||
$future->setTimeout($this->timeout);
|
||||
}
|
||||
|
||||
if ($this->getByteLimit()) {
|
||||
$future->setStdoutSizeLimit($this->getByteLimit());
|
||||
}
|
||||
|
||||
try {
|
||||
$file_content = $this->executeQueryFromFuture($future);
|
||||
} catch (CommandException $ex) {
|
||||
if (!$future->getWasKilledByTimeout()) {
|
||||
throw $ex;
|
||||
}
|
||||
|
||||
$message = pht(
|
||||
'<Attempt to load this file was terminated after %s second(s).>',
|
||||
$this->timeout);
|
||||
|
||||
$file_content = new DiffusionFileContent();
|
||||
$file_content->setCorpus($message);
|
||||
}
|
||||
|
||||
$this->fileContent = $file_content;
|
||||
|
||||
$repository = $this->getRequest()->getRepository();
|
||||
$try_encoding = $repository->getDetail('encoding');
|
||||
|
|
|
@ -84,6 +84,7 @@ final class DivinerAtomController extends DivinerController {
|
|||
if ($atom) {
|
||||
$this->buildDefined($properties, $symbol);
|
||||
$this->buildExtendsAndImplements($properties, $symbol);
|
||||
$this->buildRepository($properties, $symbol);
|
||||
|
||||
$warnings = $atom->getWarnings();
|
||||
if ($warnings) {
|
||||
|
@ -294,6 +295,15 @@ final class DivinerAtomController extends DivinerController {
|
|||
}
|
||||
}
|
||||
|
||||
private function buildRepository(
|
||||
PHUIPropertyListView $view,
|
||||
DivinerLiveSymbol $symbol) {
|
||||
|
||||
$view->addProperty(
|
||||
pht('Repository'),
|
||||
$this->getViewer()->renderHandle($symbol->getRepositoryPHID()));
|
||||
}
|
||||
|
||||
private function renderAtomTag(DivinerLiveSymbol $symbol) {
|
||||
return id(new PHUITagView())
|
||||
->setType(PHUITagView::TYPE_OBJECT)
|
||||
|
|
|
@ -14,6 +14,7 @@ final class DivinerBookController extends DivinerController {
|
|||
$book = id(new DivinerBookQuery())
|
||||
->setViewer($viewer)
|
||||
->withNames(array($book_name))
|
||||
->needRepositories(true)
|
||||
->executeOne();
|
||||
|
||||
if (!$book) {
|
||||
|
@ -43,6 +44,15 @@ final class DivinerBookController extends DivinerController {
|
|||
->setEpoch($book->getDateModified())
|
||||
->addActionLink($action_button);
|
||||
|
||||
// TODO: This could probably look better.
|
||||
if ($book->getRepositoryPHID()) {
|
||||
$header->addTag(
|
||||
id(new PHUITagView())
|
||||
->setType(PHUITagView::TYPE_STATE)
|
||||
->setBackgroundColor(PHUITagView::COLOR_BLUE)
|
||||
->setName($book->getRepository()->getMonogram()));
|
||||
}
|
||||
|
||||
$document = new PHUIDocumentView();
|
||||
$document->setHeader($header);
|
||||
$document->addClass('diviner-view');
|
||||
|
|
|
@ -75,6 +75,16 @@ final class DivinerBookEditController extends DivinerController {
|
|||
->setName('projectPHIDs')
|
||||
->setLabel(pht('Projects'))
|
||||
->setValue($book->getProjectPHIDs()))
|
||||
->appendControl(
|
||||
id(new AphrontFormTokenizerControl())
|
||||
->setDatasource(new DiffusionRepositoryDatasource())
|
||||
->setName('repositoryPHIDs')
|
||||
->setLabel(pht('Repository'))
|
||||
->setDisableBehavior(true)
|
||||
->setLimit(1)
|
||||
->setValue($book->getRepositoryPHID()
|
||||
? array($book->getRepositoryPHID())
|
||||
: null))
|
||||
->appendChild(
|
||||
id(new AphrontFormPolicyControl())
|
||||
->setName('viewPolicy')
|
||||
|
|
|
@ -4,7 +4,7 @@ final class DivinerLivePublisher extends DivinerPublisher {
|
|||
|
||||
private $book;
|
||||
|
||||
private function loadBook() {
|
||||
protected function getBook() {
|
||||
if (!$this->book) {
|
||||
$book_name = $this->getConfig('name');
|
||||
|
||||
|
@ -20,7 +20,24 @@ final class DivinerLivePublisher extends DivinerPublisher {
|
|||
->save();
|
||||
}
|
||||
|
||||
$book->setConfigurationData($this->getConfigurationData())->save();
|
||||
$conn_w = $book->establishConnection('w');
|
||||
$conn_w->openTransaction();
|
||||
|
||||
$book
|
||||
->setRepositoryPHID($this->getRepositoryPHID())
|
||||
->setConfigurationData($this->getConfigurationData())
|
||||
->save();
|
||||
|
||||
// TODO: This is gross. Without this, the repository won't be updated for
|
||||
// atoms which have already been published.
|
||||
queryfx(
|
||||
$conn_w,
|
||||
'UPDATE %T SET repositoryPHID = %s WHERE bookPHID = %s',
|
||||
id(new DivinerLiveSymbol())->getTableName(),
|
||||
$this->getRepositoryPHID(),
|
||||
$book->getPHID());
|
||||
|
||||
$conn_w->saveTransaction();
|
||||
$this->book = $book;
|
||||
|
||||
id(new PhabricatorSearchIndexer())
|
||||
|
@ -33,7 +50,7 @@ final class DivinerLivePublisher extends DivinerPublisher {
|
|||
private function loadSymbolForAtom(DivinerAtom $atom) {
|
||||
$symbol = id(new DivinerAtomQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->withBookPHIDs(array($this->loadBook()->getPHID()))
|
||||
->withBookPHIDs(array($atom->getBook()))
|
||||
->withTypes(array($atom->getType()))
|
||||
->withNames(array($atom->getName()))
|
||||
->withContexts(array($atom->getContext()))
|
||||
|
@ -45,7 +62,7 @@ final class DivinerLivePublisher extends DivinerPublisher {
|
|||
}
|
||||
|
||||
return id(new DivinerLiveSymbol())
|
||||
->setBookPHID($this->loadBook()->getPHID())
|
||||
->setBookPHID($this->getBook()->getPHID())
|
||||
->setType($atom->getType())
|
||||
->setName($atom->getName())
|
||||
->setContext($atom->getContext())
|
||||
|
@ -68,7 +85,7 @@ final class DivinerLivePublisher extends DivinerPublisher {
|
|||
protected function loadAllPublishedHashes() {
|
||||
$symbols = id(new DivinerAtomQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->withBookPHIDs(array($this->loadBook()->getPHID()))
|
||||
->withBookPHIDs(array($this->getBook()->getPHID()))
|
||||
->withGhosts(false)
|
||||
->execute();
|
||||
|
||||
|
@ -113,6 +130,7 @@ final class DivinerLivePublisher extends DivinerPublisher {
|
|||
$is_documentable = $this->shouldGenerateDocumentForAtom($atom);
|
||||
|
||||
$symbol
|
||||
->setRepositoryPHID($this->getRepositoryPHID())
|
||||
->setGraphHash($hash)
|
||||
->setIsDocumentable((int)$is_documentable)
|
||||
->setTitle($ref->getTitle())
|
||||
|
|
|
@ -9,6 +9,7 @@ abstract class DivinerPublisher extends Phobject {
|
|||
private $config;
|
||||
private $symbolReverseMap;
|
||||
private $dropCaches;
|
||||
private $repositoryPHID;
|
||||
|
||||
final public function setDropCaches($drop_caches) {
|
||||
$this->dropCaches = $drop_caches;
|
||||
|
@ -163,4 +164,13 @@ abstract class DivinerPublisher extends Phobject {
|
|||
return true;
|
||||
}
|
||||
|
||||
final public function getRepositoryPHID() {
|
||||
return $this->repositoryPHID;
|
||||
}
|
||||
|
||||
final public function setRepositoryPHID($repository_phid) {
|
||||
$this->repositoryPHID = $repository_phid;
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -14,10 +14,12 @@ final class DivinerAtomQuery extends PhabricatorCursorPagedPolicyAwareQuery {
|
|||
private $nodeHashes;
|
||||
private $titles;
|
||||
private $nameContains;
|
||||
private $repositoryPHIDs;
|
||||
|
||||
private $needAtoms;
|
||||
private $needExtends;
|
||||
private $needChildren;
|
||||
private $needRepositories;
|
||||
|
||||
public function withIDs(array $ids) {
|
||||
$this->ids = $ids;
|
||||
|
@ -109,6 +111,16 @@ final class DivinerAtomQuery extends PhabricatorCursorPagedPolicyAwareQuery {
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function withRepositoryPHIDs(array $repository_phids) {
|
||||
$this->repositoryPHIDs = $repository_phids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function needRepositories($need_repositories) {
|
||||
$this->needRepositories = $need_repositories;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function loadPage() {
|
||||
$table = new DivinerLiveSymbol();
|
||||
$conn_r = $table->establishConnection('r');
|
||||
|
@ -125,6 +137,8 @@ final class DivinerAtomQuery extends PhabricatorCursorPagedPolicyAwareQuery {
|
|||
}
|
||||
|
||||
protected function willFilterPage(array $atoms) {
|
||||
assert_instances_of($atoms, 'DivinerLiveSymbol');
|
||||
|
||||
$books = array_unique(mpull($atoms, 'getBookPHID'));
|
||||
|
||||
$books = id(new DivinerBookQuery())
|
||||
|
@ -257,6 +271,31 @@ final class DivinerAtomQuery extends PhabricatorCursorPagedPolicyAwareQuery {
|
|||
$this->attachAllChildren($atoms, $children, $this->needExtends);
|
||||
}
|
||||
|
||||
if ($this->needRepositories) {
|
||||
$repositories = id(new PhabricatorRepositoryQuery())
|
||||
->setViewer($this->getViewer())
|
||||
->withPHIDs(mpull($atoms, 'getRepositoryPHID'))
|
||||
->execute();
|
||||
$repositories = mpull($repositories, null, 'getPHID');
|
||||
|
||||
foreach ($atoms as $key => $atom) {
|
||||
if ($atom->getRepositoryPHID() === null) {
|
||||
$atom->attachRepository(null);
|
||||
continue;
|
||||
}
|
||||
|
||||
$repository = idx($repositories, $atom->getRepositoryPHID());
|
||||
|
||||
if (!$repository) {
|
||||
$this->didRejectResult($atom);
|
||||
unset($atom[$key]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$atom->attachRepository($repository);
|
||||
}
|
||||
}
|
||||
|
||||
return $atoms;
|
||||
}
|
||||
|
||||
|
@ -381,6 +420,13 @@ final class DivinerAtomQuery extends PhabricatorCursorPagedPolicyAwareQuery {
|
|||
$this->nameContains);
|
||||
}
|
||||
|
||||
if ($this->repositoryPHIDs) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'repositoryPHID IN (%Ls)',
|
||||
$this->repositoryPHIDs);
|
||||
}
|
||||
|
||||
$where[] = $this->buildPagingClause($conn_r);
|
||||
|
||||
return $this->formatWhereClause($where);
|
||||
|
|
|
@ -13,21 +13,23 @@ final class DivinerAtomSearchEngine extends PhabricatorApplicationSearchEngine {
|
|||
public function buildSavedQueryFromRequest(AphrontRequest $request) {
|
||||
$saved = new PhabricatorSavedQuery();
|
||||
|
||||
$saved->setParameter(
|
||||
'repositoryPHIDs',
|
||||
$this->readPHIDsFromRequest($request, 'repositoryPHIDs'));
|
||||
$saved->setParameter('name', $request->getStr('name'));
|
||||
$saved->setParameter(
|
||||
'types',
|
||||
$this->readListFromRequest($request, 'types'));
|
||||
|
||||
$saved->setParameter('name', $request->getStr('name'));
|
||||
|
||||
return $saved;
|
||||
}
|
||||
|
||||
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
|
||||
$query = id(new DivinerAtomQuery());
|
||||
|
||||
$types = $saved->getParameter('types');
|
||||
if ($types) {
|
||||
$query->withTypes($types);
|
||||
$repository_phids = $saved->getParameter('repositoryPHIDs');
|
||||
if ($repository_phids) {
|
||||
$query->withRepositoryPHIDs($repository_phids);
|
||||
}
|
||||
|
||||
$name = $saved->getParameter('name');
|
||||
|
@ -35,6 +37,11 @@ final class DivinerAtomSearchEngine extends PhabricatorApplicationSearchEngine {
|
|||
$query->withNameContains($name);
|
||||
}
|
||||
|
||||
$types = $saved->getParameter('types');
|
||||
if ($types) {
|
||||
$query->withTypes($types);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
|
@ -42,6 +49,12 @@ final class DivinerAtomSearchEngine extends PhabricatorApplicationSearchEngine {
|
|||
AphrontFormView $form,
|
||||
PhabricatorSavedQuery $saved) {
|
||||
|
||||
$form->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setLabel(pht('Name Contains'))
|
||||
->setName('name')
|
||||
->setValue($saved->getParameter('name')));
|
||||
|
||||
$all_types = array();
|
||||
foreach (DivinerAtom::getAllTypes() as $type) {
|
||||
$all_types[$type] = DivinerAtom::getAtomTypeNameString($type);
|
||||
|
@ -59,14 +72,14 @@ final class DivinerAtomSearchEngine extends PhabricatorApplicationSearchEngine {
|
|||
$name,
|
||||
isset($types[$type]));
|
||||
}
|
||||
$form->appendChild($type_control);
|
||||
|
||||
$form
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setLabel(pht('Name Contains'))
|
||||
->setName('name')
|
||||
->setValue($saved->getParameter('name')))
|
||||
->appendChild($type_control);
|
||||
$form->appendControl(
|
||||
id(new AphrontFormTokenizerControl())
|
||||
->setLabel(pht('Repositories'))
|
||||
->setName('repositoryPHIDs')
|
||||
->setDatasource(new DiffusionRepositoryDatasource())
|
||||
->setValue($saved->getParameter('repositoryPHIDs')));
|
||||
}
|
||||
|
||||
protected function getURI($path) {
|
||||
|
|
|
@ -5,8 +5,10 @@ final class DivinerBookQuery extends PhabricatorCursorPagedPolicyAwareQuery {
|
|||
private $ids;
|
||||
private $phids;
|
||||
private $names;
|
||||
private $repositoryPHIDs;
|
||||
|
||||
private $needProjectPHIDs;
|
||||
private $needRepositories;
|
||||
|
||||
public function withIDs(array $ids) {
|
||||
$this->ids = $ids;
|
||||
|
@ -23,11 +25,21 @@ final class DivinerBookQuery extends PhabricatorCursorPagedPolicyAwareQuery {
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function withRepositoryPHIDs(array $repository_phids) {
|
||||
$this->repositoryPHIDs = $repository_phids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function needProjectPHIDs($need_phids) {
|
||||
$this->needProjectPHIDs = $need_phids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function needRepositories($need_repositories) {
|
||||
$this->needRepositories = $need_repositories;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function loadPage() {
|
||||
$table = new DivinerLiveBook();
|
||||
$conn_r = $table->establishConnection('r');
|
||||
|
@ -46,6 +58,31 @@ final class DivinerBookQuery extends PhabricatorCursorPagedPolicyAwareQuery {
|
|||
protected function didFilterPage(array $books) {
|
||||
assert_instances_of($books, 'DivinerLiveBook');
|
||||
|
||||
if ($this->needRepositories) {
|
||||
$repositories = id(new PhabricatorRepositoryQuery())
|
||||
->setViewer($this->getViewer())
|
||||
->withPHIDs(mpull($books, 'getRepositoryPHID'))
|
||||
->execute();
|
||||
$repositories = mpull($repositories, null, 'getPHID');
|
||||
|
||||
foreach ($books as $key => $book) {
|
||||
if ($book->getRepositoryPHID() === null) {
|
||||
$book->attachRepository(null);
|
||||
continue;
|
||||
}
|
||||
|
||||
$repository = idx($repositories, $book->getRepositoryPHID());
|
||||
|
||||
if (!$repository) {
|
||||
$this->didRejectResult($book);
|
||||
unset($books[$key]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$book->attachRepository($repository);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->needProjectPHIDs) {
|
||||
$edge_query = id(new PhabricatorEdgeQuery())
|
||||
->withSourcePHIDs(mpull($books, 'getPHID'))
|
||||
|
@ -91,6 +128,13 @@ final class DivinerBookQuery extends PhabricatorCursorPagedPolicyAwareQuery {
|
|||
$this->names);
|
||||
}
|
||||
|
||||
if ($this->repositoryPHIDs !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'repositoryPHID IN (%Ls)',
|
||||
$this->repositoryPHIDs);
|
||||
}
|
||||
|
||||
$where[] = $this->buildPagingClause($conn_r);
|
||||
|
||||
return $this->formatWhereClause($where);
|
||||
|
|
|
@ -29,6 +29,12 @@ final class DivinerAtomSearchIndexer extends PhabricatorSearchDocumentIndexer {
|
|||
DivinerBookPHIDType::TYPECONST,
|
||||
PhabricatorTime::getNow());
|
||||
|
||||
$doc->addRelationship(
|
||||
PhabricatorSearchRelationship::RELATIONSHIP_REPOSITORY,
|
||||
$atom->getRepositoryPHID(),
|
||||
PhabricatorRepositoryRepositoryPHIDType::TYPECONST,
|
||||
PhabricatorTime::getNow());
|
||||
|
||||
$doc->addRelationship(
|
||||
$atom->getGraphHash()
|
||||
? PhabricatorSearchRelationship::RELATIONSHIP_CLOSED
|
||||
|
|
|
@ -18,6 +18,12 @@ final class DivinerBookSearchIndexer extends PhabricatorSearchDocumentIndexer {
|
|||
PhabricatorSearchDocumentFieldType::FIELD_BODY,
|
||||
$book->getPreface());
|
||||
|
||||
$doc->addRelationship(
|
||||
PhabricatorSearchRelationship::RELATIONSHIP_REPOSITORY,
|
||||
$book->getRepositoryPHID(),
|
||||
PhabricatorRepositoryRepositoryPHIDType::TYPECONST,
|
||||
$book->getDateCreated());
|
||||
|
||||
$this->indexTransactions(
|
||||
$doc,
|
||||
new DivinerLiveBookTransactionQuery(),
|
||||
|
|
|
@ -8,11 +8,13 @@ final class DivinerLiveBook extends DivinerDAO
|
|||
PhabricatorApplicationTransactionInterface {
|
||||
|
||||
protected $name;
|
||||
protected $repositoryPHID;
|
||||
protected $viewPolicy;
|
||||
protected $editPolicy;
|
||||
protected $configurationData = array();
|
||||
|
||||
private $projectPHIDs = self::ATTACHABLE;
|
||||
private $repository = self::ATTACHABLE;
|
||||
|
||||
protected function getConfiguration() {
|
||||
return array(
|
||||
|
@ -22,6 +24,7 @@ final class DivinerLiveBook extends DivinerDAO
|
|||
),
|
||||
self::CONFIG_COLUMN_SCHEMA => array(
|
||||
'name' => 'text64',
|
||||
'repositoryPHID' => 'phid?',
|
||||
),
|
||||
self::CONFIG_KEY_SCHEMA => array(
|
||||
'key_phid' => null,
|
||||
|
@ -68,6 +71,15 @@ final class DivinerLiveBook extends DivinerDAO
|
|||
return idx($spec, 'name', $group);
|
||||
}
|
||||
|
||||
public function attachRepository(PhabricatorRepository $repository = null) {
|
||||
$this->repository = $repository;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRepository() {
|
||||
return $this->assertAttached($this->repository);
|
||||
}
|
||||
|
||||
public function attachProjectPHIDs(array $project_phids) {
|
||||
$this->projectPHIDs = $project_phids;
|
||||
return $this;
|
||||
|
@ -98,7 +110,7 @@ final class DivinerLiveBook extends DivinerDAO
|
|||
}
|
||||
|
||||
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
public function describeAutomaticCapability($capability) {
|
||||
|
|
|
@ -7,6 +7,7 @@ final class DivinerLiveSymbol extends DivinerDAO
|
|||
PhabricatorDestructibleInterface {
|
||||
|
||||
protected $bookPHID;
|
||||
protected $repositoryPHID;
|
||||
protected $context;
|
||||
protected $type;
|
||||
protected $name;
|
||||
|
@ -22,6 +23,7 @@ final class DivinerLiveSymbol extends DivinerDAO
|
|||
protected $isDocumentable = 0;
|
||||
|
||||
private $book = self::ATTACHABLE;
|
||||
private $repository = self::ATTACHABLE;
|
||||
private $atom = self::ATTACHABLE;
|
||||
private $extends = self::ATTACHABLE;
|
||||
private $children = self::ATTACHABLE;
|
||||
|
@ -43,6 +45,7 @@ final class DivinerLiveSymbol extends DivinerDAO
|
|||
'summary' => 'text?',
|
||||
'isDocumentable' => 'bool',
|
||||
'nodeHash' => 'text64?',
|
||||
'repositoryPHID' => 'phid?',
|
||||
),
|
||||
self::CONFIG_KEY_SCHEMA => array(
|
||||
'key_phid' => null,
|
||||
|
@ -94,6 +97,15 @@ final class DivinerLiveSymbol extends DivinerDAO
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function getRepository() {
|
||||
return $this->assertAttached($this->repository);
|
||||
}
|
||||
|
||||
public function attachRepository(PhabricatorRepository $repository = null) {
|
||||
$this->repository = $repository;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAtom() {
|
||||
return $this->assertAttached($this->atom);
|
||||
}
|
||||
|
|
|
@ -25,6 +25,11 @@ final class DivinerGenerateWorkflow extends DivinerWorkflow {
|
|||
'help' => pht('Specify a subclass of %s.', 'DivinerPublisher'),
|
||||
'default' => 'DivinerLivePublisher',
|
||||
),
|
||||
array(
|
||||
'name' => 'repository',
|
||||
'param' => 'callsign',
|
||||
'help' => pht('Repository that the documentation belongs to.'),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -187,6 +192,24 @@ final class DivinerGenerateWorkflow extends DivinerWorkflow {
|
|||
}
|
||||
$publisher = newv($publisher_class, array());
|
||||
|
||||
$callsign = $args->getArg('repository');
|
||||
$repository = null;
|
||||
if ($callsign) {
|
||||
$repository = id(new PhabricatorRepositoryQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->withCallsigns(array($callsign))
|
||||
->executeOne();
|
||||
|
||||
if (!$repository) {
|
||||
throw new PhutilArgumentUsageException(
|
||||
pht(
|
||||
"Repository '%s' does not exist.",
|
||||
$callsign));
|
||||
}
|
||||
|
||||
$publisher->setRepositoryPHID($repository->getPHID());
|
||||
}
|
||||
|
||||
$this->publishDocumentation($args->getArg('clean'), $publisher);
|
||||
}
|
||||
|
||||
|
|
|
@ -77,20 +77,7 @@ final class DrydockPreallocatedHostBlueprintImplementation
|
|||
|
||||
$cmd = $lease->getInterface('command');
|
||||
|
||||
if ($v_platform !== 'windows') {
|
||||
$cmd->execx('mkdir %s', $full_path);
|
||||
} else {
|
||||
// Windows is terrible. The mkdir command doesn't even support putting
|
||||
// the path in quotes. IN QUOTES. ARGUHRGHUGHHGG!! Do some terribly
|
||||
// inaccurate sanity checking since we can't safely escape the path.
|
||||
if (preg_match('/^[A-Z]\\:\\\\[a-zA-Z0-9\\\\\\ ]/', $full_path) === 0) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Unsafe path detected for Windows platform: "%s".',
|
||||
$full_path));
|
||||
}
|
||||
$cmd->execx('mkdir %C', $full_path);
|
||||
}
|
||||
$cmd->execx('mkdir %s', $full_path);
|
||||
|
||||
$lease->setAttribute('path', $full_path);
|
||||
}
|
||||
|
|
|
@ -42,46 +42,8 @@ final class DrydockSSHCommandInterface extends DrydockCommandInterface {
|
|||
$this->openCredentialsIfNotOpen();
|
||||
|
||||
$argv = func_get_args();
|
||||
|
||||
if ($this->getConfig('platform') === 'windows') {
|
||||
// Handle Windows by executing the command under PowerShell.
|
||||
$command = id(new PhutilCommandString($argv))
|
||||
->setEscapingMode(PhutilCommandString::MODE_POWERSHELL);
|
||||
|
||||
$change_directory = '';
|
||||
if ($this->getWorkingDirectory() !== null) {
|
||||
$change_directory .= 'cd '.$this->getWorkingDirectory();
|
||||
}
|
||||
|
||||
$script = <<<EOF
|
||||
$change_directory
|
||||
$command
|
||||
if (\$LastExitCode -ne 0) {
|
||||
exit \$LastExitCode
|
||||
}
|
||||
EOF;
|
||||
|
||||
// When Microsoft says "Unicode" they don't mean UTF-8.
|
||||
$script = mb_convert_encoding($script, 'UTF-16LE');
|
||||
|
||||
$script = base64_encode($script);
|
||||
|
||||
$powershell =
|
||||
'C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe';
|
||||
$powershell .=
|
||||
' -ExecutionPolicy Bypass'.
|
||||
' -NonInteractive'.
|
||||
' -InputFormat Text'.
|
||||
' -OutputFormat Text'.
|
||||
' -EncodedCommand '.$script;
|
||||
|
||||
$full_command = $powershell;
|
||||
} else {
|
||||
// Handle UNIX by executing under the native shell.
|
||||
$argv = $this->applyWorkingDirectoryToArgv($argv);
|
||||
|
||||
$full_command = call_user_func_array('csprintf', $argv);
|
||||
}
|
||||
$argv = $this->applyWorkingDirectoryToArgv($argv);
|
||||
$full_command = call_user_func_array('csprintf', $argv);
|
||||
|
||||
$command_timeout = '';
|
||||
if ($this->connectTimeout !== null) {
|
||||
|
|
|
@ -7,6 +7,7 @@ final class PhabricatorOwnersPackageQuery
|
|||
private $phids;
|
||||
private $ownerPHIDs;
|
||||
private $repositoryPHIDs;
|
||||
private $namePrefix;
|
||||
|
||||
/**
|
||||
* Owners are direct owners, and members of owning projects.
|
||||
|
@ -31,62 +32,59 @@ final class PhabricatorOwnersPackageQuery
|
|||
return $this;
|
||||
}
|
||||
|
||||
protected function loadPage() {
|
||||
$table = new PhabricatorOwnersPackage();
|
||||
$conn_r = $table->establishConnection('r');
|
||||
|
||||
$data = queryfx_all(
|
||||
$conn_r,
|
||||
'SELECT p.* FROM %T p %Q %Q %Q %Q',
|
||||
$table->getTableName(),
|
||||
$this->buildJoinClause($conn_r),
|
||||
$this->buildWhereClause($conn_r),
|
||||
$this->buildOrderClause($conn_r),
|
||||
$this->buildLimitClause($conn_r));
|
||||
|
||||
return $table->loadAllFromArray($data);
|
||||
public function withNamePrefix($prefix) {
|
||||
$this->namePrefix = $prefix;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function buildJoinClause(AphrontDatabaseConnection $conn_r) {
|
||||
$joins = array();
|
||||
public function newResultObject() {
|
||||
return new PhabricatorOwnersPackage();
|
||||
}
|
||||
|
||||
protected function loadPage() {
|
||||
return $this->loadStandardPage(new PhabricatorOwnersPackage());
|
||||
}
|
||||
|
||||
protected function buildJoinClauseParts(AphrontDatabaseConnection $conn) {
|
||||
$joins = parent::buildJoinClauseParts($conn);
|
||||
|
||||
if ($this->ownerPHIDs !== null) {
|
||||
$joins[] = qsprintf(
|
||||
$conn_r,
|
||||
$conn,
|
||||
'JOIN %T o ON o.packageID = p.id',
|
||||
id(new PhabricatorOwnersOwner())->getTableName());
|
||||
}
|
||||
|
||||
if ($this->repositoryPHIDs !== null) {
|
||||
$joins[] = qsprintf(
|
||||
$conn_r,
|
||||
$conn,
|
||||
'JOIN %T rpath ON rpath.packageID = p.id',
|
||||
id(new PhabricatorOwnersPath())->getTableName());
|
||||
}
|
||||
|
||||
return implode(' ', $joins);
|
||||
return $joins;
|
||||
}
|
||||
|
||||
protected function buildWhereClause(AphrontDatabaseConnection $conn_r) {
|
||||
$where = array();
|
||||
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
|
||||
$where = parent::buildWhereClauseParts($conn);
|
||||
|
||||
if ($this->phids !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
$conn,
|
||||
'p.phid IN (%Ls)',
|
||||
$this->phids);
|
||||
}
|
||||
|
||||
if ($this->ids !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
$conn,
|
||||
'p.id IN (%Ld)',
|
||||
$this->ids);
|
||||
}
|
||||
|
||||
if ($this->repositoryPHIDs !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
$conn,
|
||||
'rpath.repositoryPHID IN (%Ls)',
|
||||
$this->repositoryPHIDs);
|
||||
}
|
||||
|
@ -94,26 +92,79 @@ final class PhabricatorOwnersPackageQuery
|
|||
if ($this->ownerPHIDs !== null) {
|
||||
$base_phids = $this->ownerPHIDs;
|
||||
|
||||
$query = new PhabricatorProjectQuery();
|
||||
$query->setViewer($this->getViewer());
|
||||
$query->withMemberPHIDs($base_phids);
|
||||
$projects = $query->execute();
|
||||
$projects = id(new PhabricatorProjectQuery())
|
||||
->setViewer($this->getViewer())
|
||||
->withMemberPHIDs($base_phids)
|
||||
->execute();
|
||||
$project_phids = mpull($projects, 'getPHID');
|
||||
|
||||
$all_phids = array_merge($base_phids, $project_phids);
|
||||
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
$conn,
|
||||
'o.userPHID IN (%Ls)',
|
||||
$all_phids);
|
||||
}
|
||||
|
||||
$where[] = $this->buildPagingClause($conn_r);
|
||||
return $this->formatWhereClause($where);
|
||||
if (strlen($this->namePrefix)) {
|
||||
// NOTE: This is a hacky mess, but this column is currently case
|
||||
// sensitive and unique.
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'LOWER(p.name) LIKE %>',
|
||||
phutil_utf8_strtolower($this->namePrefix));
|
||||
}
|
||||
|
||||
return $where;
|
||||
}
|
||||
|
||||
protected function shouldGroupQueryResultRows() {
|
||||
if ($this->repositoryPHIDs) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->ownerPHIDs) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return parent::shouldGroupQueryResultRows();
|
||||
}
|
||||
|
||||
public function getBuiltinOrders() {
|
||||
return array(
|
||||
'name' => array(
|
||||
'vector' => array('name'),
|
||||
'name' => pht('Name'),
|
||||
),
|
||||
) + parent::getBuiltinOrders();
|
||||
}
|
||||
|
||||
public function getOrderableColumns() {
|
||||
return parent::getOrderableColumns() + array(
|
||||
'name' => array(
|
||||
'table' => $this->getPrimaryTableAlias(),
|
||||
'column' => 'name',
|
||||
'type' => 'string',
|
||||
'unique' => true,
|
||||
'reverse' => true,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
protected function getPagingValueMap($cursor, array $keys) {
|
||||
$package = $this->loadCursorObject($cursor);
|
||||
return array(
|
||||
'id' => $package->getID(),
|
||||
'name' => $package->getName(),
|
||||
);
|
||||
}
|
||||
|
||||
public function getQueryApplicationClass() {
|
||||
return 'PhabricatorOwnersApplication';
|
||||
}
|
||||
|
||||
protected function getPrimaryTableAlias() {
|
||||
return 'p';
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,68 +11,39 @@ final class PhabricatorOwnersPackageSearchEngine
|
|||
return 'PhabricatorOwnersApplication';
|
||||
}
|
||||
|
||||
public function buildSavedQueryFromRequest(AphrontRequest $request) {
|
||||
$saved = new PhabricatorSavedQuery();
|
||||
|
||||
$saved->setParameter(
|
||||
'ownerPHIDs',
|
||||
$this->readUsersFromRequest(
|
||||
$request,
|
||||
'owners',
|
||||
array(
|
||||
PhabricatorProjectProjectPHIDType::TYPECONST,
|
||||
)));
|
||||
|
||||
$saved->setParameter(
|
||||
'repositoryPHIDs',
|
||||
$this->readPHIDsFromRequest(
|
||||
$request,
|
||||
'repositories',
|
||||
array(
|
||||
PhabricatorRepositoryRepositoryPHIDType::TYPECONST,
|
||||
)));
|
||||
|
||||
return $saved;
|
||||
public function newQuery() {
|
||||
return new PhabricatorOwnersPackageQuery();
|
||||
}
|
||||
|
||||
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
|
||||
$query = id(new PhabricatorOwnersPackageQuery());
|
||||
protected function buildCustomSearchFields() {
|
||||
return array(
|
||||
id(new PhabricatorSearchDatasourceField())
|
||||
->setLabel(pht('Owners'))
|
||||
->setKey('ownerPHIDs')
|
||||
->setAliases(array('owner', 'owners'))
|
||||
->setDatasource(new PhabricatorProjectOrUserDatasource()),
|
||||
id(new PhabricatorSearchDatasourceField())
|
||||
->setLabel(pht('Repositories'))
|
||||
->setKey('repositoryPHIDs')
|
||||
->setAliases(array('repository', 'repositories'))
|
||||
->setDatasource(new DiffusionRepositoryDatasource()),
|
||||
);
|
||||
}
|
||||
|
||||
$owner_phids = $saved->getParameter('ownerPHIDs', array());
|
||||
if ($owner_phids) {
|
||||
$query->withOwnerPHIDs($owner_phids);
|
||||
protected function buildQueryFromParameters(array $map) {
|
||||
$query = $this->newQuery();
|
||||
|
||||
if ($map['ownerPHIDs']) {
|
||||
$query->withOwnerPHIDs($map['ownerPHIDs']);
|
||||
}
|
||||
|
||||
$repository_phids = $saved->getParameter('repositoryPHIDs', array());
|
||||
if ($repository_phids) {
|
||||
$query->withRepositoryPHIDs($repository_phids);
|
||||
if ($map['repositoryPHIDs']) {
|
||||
$query->withRepositoryPHIDs($map['repositoryPHIDs']);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
public function buildSearchForm(
|
||||
AphrontFormView $form,
|
||||
PhabricatorSavedQuery $saved) {
|
||||
|
||||
$owner_phids = $saved->getParameter('ownerPHIDs', array());
|
||||
$repository_phids = $saved->getParameter('repositoryPHIDs', array());
|
||||
|
||||
$form
|
||||
->appendControl(
|
||||
id(new AphrontFormTokenizerControl())
|
||||
->setDatasource(new PhabricatorProjectOrUserDatasource())
|
||||
->setName('owners')
|
||||
->setLabel(pht('Owners'))
|
||||
->setValue($owner_phids))
|
||||
->appendControl(
|
||||
id(new AphrontFormTokenizerControl())
|
||||
->setDatasource(new DiffusionRepositoryDatasource())
|
||||
->setName('repositories')
|
||||
->setLabel(pht('Repositories'))
|
||||
->setValue($repository_phids));
|
||||
}
|
||||
|
||||
protected function getURI($path) {
|
||||
return '/owners/'.$path;
|
||||
}
|
||||
|
|
|
@ -3,11 +3,6 @@
|
|||
final class PhabricatorOwnersPackageDatasource
|
||||
extends PhabricatorTypeaheadDatasource {
|
||||
|
||||
public function isBrowsable() {
|
||||
// TODO: Make this browsable.
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getBrowseTitle() {
|
||||
return pht('Browse Packages');
|
||||
}
|
||||
|
@ -26,10 +21,11 @@ final class PhabricatorOwnersPackageDatasource
|
|||
|
||||
$results = array();
|
||||
|
||||
$packages = id(new PhabricatorOwnersPackageQuery())
|
||||
->setViewer($viewer)
|
||||
->execute();
|
||||
$query = id(new PhabricatorOwnersPackageQuery())
|
||||
->withNamePrefix($raw_query)
|
||||
->setOrder('name');
|
||||
|
||||
$packages = $this->executeQuery($query);
|
||||
foreach ($packages as $package) {
|
||||
$results[] = id(new PhabricatorTypeaheadResult())
|
||||
->setName($package->getName())
|
||||
|
@ -37,7 +33,7 @@ final class PhabricatorOwnersPackageDatasource
|
|||
->setPHID($package->getPHID());
|
||||
}
|
||||
|
||||
return $results;
|
||||
return $this->filterResultsAgainstTokens($results);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -738,6 +738,41 @@ final class PhabricatorUser
|
|||
return new DateTimeZone($this->getTimezoneIdentifier());
|
||||
}
|
||||
|
||||
public function getPreference($key) {
|
||||
$preferences = $this->loadPreferences();
|
||||
|
||||
// TODO: After T4103 and T7707 this should eventually be pushed down the
|
||||
// stack into modular preference definitions and role profiles. This is
|
||||
// just fixing T8601 and mildly anticipating those changes.
|
||||
$value = $preferences->getPreference($key);
|
||||
|
||||
$allowed_values = null;
|
||||
switch ($key) {
|
||||
case PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT:
|
||||
$allowed_values = array(
|
||||
'g:i A',
|
||||
'H:i',
|
||||
);
|
||||
break;
|
||||
case PhabricatorUserPreferences::PREFERENCE_DATE_FORMAT:
|
||||
$allowed_values = array(
|
||||
'Y-m-d',
|
||||
'n/j/Y',
|
||||
'd-m-Y',
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
if ($allowed_values !== null) {
|
||||
$allowed_values = array_fuse($allowed_values);
|
||||
if (empty($allowed_values[$value])) {
|
||||
$value = head($allowed_values);
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function __toString() {
|
||||
return $this->getUsername();
|
||||
}
|
||||
|
|
|
@ -1913,7 +1913,25 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
|
|||
PhabricatorDestructionEngine $engine) {
|
||||
|
||||
$this->openTransaction();
|
||||
$this->delete();
|
||||
|
||||
$this->delete();
|
||||
|
||||
$books = id(new DivinerBookQuery())
|
||||
->setViewer($engine->getViewer())
|
||||
->withRepositoryPHIDs(array($this->getPHID()))
|
||||
->execute();
|
||||
foreach ($books as $book) {
|
||||
$engine->destroyObject($book);
|
||||
}
|
||||
|
||||
$atoms = id(new DivinerAtomQuery())
|
||||
->setViewer($engine->getViewer())
|
||||
->withRepositoryPHIDs(array($this->getPHID()))
|
||||
->execute();
|
||||
foreach ($atoms as $atom) {
|
||||
$engine->destroyObject($atom);
|
||||
}
|
||||
|
||||
$this->saveTransaction();
|
||||
}
|
||||
|
||||
|
|
|
@ -199,7 +199,8 @@ abstract class PhabricatorWorker extends Phobject {
|
|||
}
|
||||
|
||||
$tasks = id(new PhabricatorWorkerArchiveTaskQuery())
|
||||
->withIDs($task_ids);
|
||||
->withIDs($task_ids)
|
||||
->execute();
|
||||
|
||||
foreach ($tasks as $task) {
|
||||
if ($task->getResult() != PhabricatorWorkerArchiveTask::RESULT_SUCCESS) {
|
||||
|
|
|
@ -198,10 +198,7 @@ final class PhabricatorMarkupEngine extends Phobject {
|
|||
}
|
||||
|
||||
if (!isset($this->objects[$key]['output'])) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Call %s before using results.',
|
||||
'process()'));
|
||||
throw new PhutilInvalidStateException('process');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -45,34 +45,57 @@ final class PhabricatorStorageManagementProbeWorkflow
|
|||
}
|
||||
}
|
||||
|
||||
$console->writeOut("%s\n", pht('APPROXIMATE TABLE SIZES'));
|
||||
asort($totals);
|
||||
|
||||
$table = id(new PhutilConsoleTable())
|
||||
->setShowHeader(false)
|
||||
->setPadding(2)
|
||||
->addColumn('name', array('title' => pht('Database / Table')))
|
||||
->addColumn('size', array('title' => pht('Size')))
|
||||
->addColumn('percentage', array('title' => pht('Percentage')));
|
||||
|
||||
foreach ($totals as $db => $size) {
|
||||
$database_size = $this->formatSize($totals[$db], $overall);
|
||||
$console->writeOut(
|
||||
"**%s**\n",
|
||||
sprintf('%-32.32s %18s', $db, $database_size));
|
||||
list($database_size, $database_percentage) = $this->formatSize(
|
||||
$totals[$db],
|
||||
$overall);
|
||||
|
||||
$table->addRow(array(
|
||||
'name' => phutil_console_format('**%s**', $db),
|
||||
'size' => phutil_console_format('**%s**', $database_size),
|
||||
'percentage' => phutil_console_format('**%s**', $database_percentage),
|
||||
));
|
||||
$data[$db] = isort($data[$db], '_totalSize');
|
||||
foreach ($data[$db] as $table => $info) {
|
||||
$table_size = $this->formatSize($info['_totalSize'], $overall);
|
||||
$console->writeOut(
|
||||
"%s\n",
|
||||
sprintf(' %-28.28s %18s', $table, $table_size));
|
||||
foreach ($data[$db] as $table_name => $info) {
|
||||
list($table_size, $table_percentage) = $this->formatSize(
|
||||
$info['_totalSize'],
|
||||
$overall);
|
||||
|
||||
$table->addRow(array(
|
||||
'name' => ' '.$table_name,
|
||||
'size' => $table_size,
|
||||
'percentage' => $table_percentage,
|
||||
));
|
||||
}
|
||||
}
|
||||
$overall_size = $this->formatSize($overall, $overall);
|
||||
$console->writeOut(
|
||||
"**%s**\n",
|
||||
sprintf('%-32.32s %18s', pht('TOTAL'), $overall_size));
|
||||
|
||||
list($overall_size, $overall_percentage) = $this->formatSize(
|
||||
$overall,
|
||||
$overall);
|
||||
$table->addRow(array(
|
||||
'name' => phutil_console_format('**%s**', pht('TOTAL')),
|
||||
'size' => phutil_console_format('**%s**', $overall_size),
|
||||
'percentage' => phutil_console_format('**%s**', $overall_percentage),
|
||||
));
|
||||
|
||||
$table->draw();
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function formatSize($n, $o) {
|
||||
return sprintf(
|
||||
'%8.8s MB %5.5s%%',
|
||||
number_format($n / (1024 * 1024), 1),
|
||||
sprintf('%3.1f', 100 * ($n / $o)));
|
||||
return array(
|
||||
sprintf('%8.8s MB', number_format($n / (1024 * 1024), 1)),
|
||||
sprintf('%3.1f%%', 100 * ($n / $o)),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -137,19 +137,13 @@ final class AphrontFormDateControl extends AphrontFormControl {
|
|||
}
|
||||
|
||||
private function getTimeFormat() {
|
||||
$viewer = $this->getUser();
|
||||
$preferences = $viewer->loadPreferences();
|
||||
$pref_time_format = PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT;
|
||||
|
||||
return $preferences->getPreference($pref_time_format, 'g:i A');
|
||||
return $this->getUser()
|
||||
->getPreference(PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT);
|
||||
}
|
||||
|
||||
private function getDateFormat() {
|
||||
$viewer = $this->getUser();
|
||||
$preferences = $viewer->loadPreferences();
|
||||
$pref_date_format = PhabricatorUserPreferences::PREFERENCE_DATE_FORMAT;
|
||||
|
||||
return $preferences->getPreference($pref_date_format, 'Y-m-d');
|
||||
return $this->getUser()
|
||||
->getPreference(PhabricatorUserPreferences::PREFERENCE_DATE_FORMAT);
|
||||
}
|
||||
|
||||
private function getTimeInputValue() {
|
||||
|
|
|
@ -10,7 +10,6 @@ final class AphrontFormDateControlValue extends Phobject {
|
|||
private $zone;
|
||||
private $optional;
|
||||
|
||||
|
||||
public function getValueDate() {
|
||||
return $this->valueDate;
|
||||
}
|
||||
|
@ -56,6 +55,10 @@ final class AphrontFormDateControlValue extends Phobject {
|
|||
return $this->optional;
|
||||
}
|
||||
|
||||
public function getViewer() {
|
||||
return $this->viewer;
|
||||
}
|
||||
|
||||
public static function newFromParts(
|
||||
PhabricatorUser $viewer,
|
||||
$year,
|
||||
|
@ -71,8 +74,7 @@ final class AphrontFormDateControlValue extends Phobject {
|
|||
$year,
|
||||
$month,
|
||||
$day,
|
||||
coalesce($time, '12:00 AM'),
|
||||
$value);
|
||||
coalesce($time, '12:00 AM'));
|
||||
$value->valueEnabled = $enabled;
|
||||
|
||||
return $value;
|
||||
|
@ -85,8 +87,7 @@ final class AphrontFormDateControlValue extends Phobject {
|
|||
list($value->valueDate, $value->valueTime) =
|
||||
$value->getFormattedDateFromDate(
|
||||
$request->getStr($key.'_d'),
|
||||
$request->getStr($key.'_t'),
|
||||
$value);
|
||||
$request->getStr($key.'_t'));
|
||||
|
||||
$value->valueEnabled = $request->getStr($key.'_e');
|
||||
return $value;
|
||||
|
@ -108,8 +109,7 @@ final class AphrontFormDateControlValue extends Phobject {
|
|||
$year,
|
||||
$month,
|
||||
$day,
|
||||
$time,
|
||||
$value);
|
||||
$time);
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
@ -123,8 +123,7 @@ final class AphrontFormDateControlValue extends Phobject {
|
|||
list($value->valueDate, $value->valueTime) =
|
||||
$value->getFormattedDateFromDate(
|
||||
idx($dictionary, 'd'),
|
||||
idx($dictionary, 't'),
|
||||
$value);
|
||||
idx($dictionary, 't'));
|
||||
|
||||
$value->valueEnabled = idx($dictionary, 'e');
|
||||
|
||||
|
@ -205,29 +204,25 @@ final class AphrontFormDateControlValue extends Phobject {
|
|||
}
|
||||
|
||||
private function getTimeFormat() {
|
||||
$preferences = $this->viewer->loadPreferences();
|
||||
$pref_time_format = PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT;
|
||||
|
||||
return $preferences->getPreference($pref_time_format, 'g:i A');
|
||||
return $this->getViewer()
|
||||
->getPreference(PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT);
|
||||
}
|
||||
|
||||
private function getDateFormat() {
|
||||
$preferences = $this->viewer->loadPreferences();
|
||||
$pref_date_format = PhabricatorUserPreferences::PREFERENCE_DATE_FORMAT;
|
||||
|
||||
return $preferences->getPreference($pref_date_format, 'Y-m-d');
|
||||
return $this->getViewer()
|
||||
->getPreference(PhabricatorUserPreferences::PREFERENCE_DATE_FORMAT);
|
||||
}
|
||||
|
||||
private function getFormattedDateFromDate($date, $time, $value) {
|
||||
private function getFormattedDateFromDate($date, $time) {
|
||||
$original_input = $date;
|
||||
$zone = $value->getTimezone();
|
||||
$separator = $value->getFormatSeparator();
|
||||
$zone = $this->getTimezone();
|
||||
$separator = $this->getFormatSeparator();
|
||||
$parts = preg_split('@[,./:-]@', $date);
|
||||
$date = implode($separator, $parts);
|
||||
$date = id(new DateTime($date, $zone));
|
||||
|
||||
if ($date) {
|
||||
$date = $date->format($value->getDateFormat());
|
||||
$date = $date->format($this->getDateFormat());
|
||||
} else {
|
||||
$date = $original_input;
|
||||
}
|
||||
|
@ -235,8 +230,8 @@ final class AphrontFormDateControlValue extends Phobject {
|
|||
$date = id(new DateTime("{$date} {$time}", $zone));
|
||||
|
||||
return array(
|
||||
$date->format($value->getDateFormat()),
|
||||
$date->format($value->getTimeFormat()),
|
||||
$date->format($this->getDateFormat()),
|
||||
$date->format($this->getTimeFormat()),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -244,14 +239,14 @@ final class AphrontFormDateControlValue extends Phobject {
|
|||
$year,
|
||||
$month,
|
||||
$day,
|
||||
$time,
|
||||
$value) {
|
||||
$zone = $value->getTimezone();
|
||||
$time) {
|
||||
|
||||
$zone = $this->getTimezone();
|
||||
$date_time = id(new DateTime("{$year}-{$month}-{$day} {$time}", $zone));
|
||||
|
||||
return array(
|
||||
$date_time->format($value->getDateFormat()),
|
||||
$date_time->format($value->getTimeFormat()),
|
||||
$date_time->format($this->getDateFormat()),
|
||||
$date_time->format($this->getTimeFormat()),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -162,10 +162,10 @@ final class AphrontFormPolicyControl extends AphrontFormControl {
|
|||
|
||||
protected function renderInput() {
|
||||
if (!$this->object) {
|
||||
throw new Exception(pht('Call setPolicyObject() before rendering!'));
|
||||
throw new PhutilInvalidStateException('setPolicyObject');
|
||||
}
|
||||
if (!$this->capability) {
|
||||
throw new Exception(pht('Call setCapability() before rendering!'));
|
||||
throw new PhutilInvalidStateException('setCapability');
|
||||
}
|
||||
|
||||
$policy = $this->object->getPolicy($this->capability);
|
||||
|
|
|
@ -109,8 +109,11 @@ final class AphrontFormTokenizerControl extends AphrontFormControl {
|
|||
if (!$viewer) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Call setUser() before rendering tokenizers. Use appendControl() '.
|
||||
'on AphrontFormView to do this easily.'));
|
||||
'Call %s before rendering tokenizers. '.
|
||||
'Use %s on %s to do this easily.',
|
||||
'setUser()',
|
||||
'appendControl()',
|
||||
'AphrontFormView'));
|
||||
}
|
||||
|
||||
$values = nonempty($this->getValue(), array());
|
||||
|
|
|
@ -187,10 +187,10 @@ final class AphrontSideNavFilterView extends AphrontView {
|
|||
public function render() {
|
||||
if ($this->menu->getItems()) {
|
||||
if (!$this->baseURI) {
|
||||
throw new Exception(pht('Call setBaseURI() before render()!'));
|
||||
throw new PhutilInvalidStateException('setBaseURI');
|
||||
}
|
||||
if ($this->selectedFilter === false) {
|
||||
throw new Exception(pht('Call selectFilter() before render()!'));
|
||||
throw new PhutilInvalidStateException('selectFilter');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ final class PhabricatorActionListView extends AphrontView {
|
|||
|
||||
public function render() {
|
||||
if (!$this->user) {
|
||||
throw new Exception(pht('Call setUser() before render()!'));
|
||||
throw new PhutilInvalidStateException('setUser');
|
||||
}
|
||||
|
||||
$event = new PhabricatorEvent(
|
||||
|
|
|
@ -144,7 +144,7 @@ final class PHUITagView extends AphrontTagView {
|
|||
|
||||
protected function getTagContent() {
|
||||
if (!$this->type) {
|
||||
throw new Exception(pht('You must call setType() before render()!'));
|
||||
throw new PhutilInvalidStateException('setType', 'render');
|
||||
}
|
||||
|
||||
$color = null;
|
||||
|
|
|
@ -141,11 +141,8 @@ final class PHUICalendarListView extends AphrontTagView {
|
|||
}
|
||||
|
||||
private function getEventTooltip(AphrontCalendarEventView $event) {
|
||||
$viewer = $this->getUser();
|
||||
$preferences = $viewer->loadPreferences();
|
||||
$time_pref = $preferences->getPreference(
|
||||
PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT,
|
||||
'g:i A');
|
||||
$time_pref = $this->getUser()
|
||||
->getPreference(PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT);
|
||||
|
||||
Javelin::initBehavior('phabricator-tooltips');
|
||||
|
||||
|
|
|
@ -31,32 +31,21 @@ function phabricator_relative_date($epoch, $user, $on = false) {
|
|||
}
|
||||
|
||||
function phabricator_time($epoch, $user) {
|
||||
$time_key = PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT;
|
||||
return phabricator_format_local_time(
|
||||
$epoch,
|
||||
$user,
|
||||
phabricator_time_format($user));
|
||||
$user->getPreference($time_key));
|
||||
}
|
||||
|
||||
function phabricator_datetime($epoch, $user) {
|
||||
$time_key = PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT;
|
||||
return phabricator_format_local_time(
|
||||
$epoch,
|
||||
$user,
|
||||
pht('%s, %s',
|
||||
phutil_date_format($epoch),
|
||||
phabricator_time_format($user)));
|
||||
}
|
||||
|
||||
function phabricator_time_format($user) {
|
||||
$prefs = $user->loadPreferences();
|
||||
|
||||
$pref = $prefs->getPreference(
|
||||
PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT);
|
||||
|
||||
if (strlen($pref)) {
|
||||
return $pref;
|
||||
}
|
||||
|
||||
return pht('g:i A');
|
||||
$user->getPreference($time_key)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -99,8 +99,20 @@ JX.behavior('phabricator-remarkup-assist', function(config) {
|
|||
} else {
|
||||
sel = [def];
|
||||
}
|
||||
sel = sel.join('\n' + ch);
|
||||
return sel;
|
||||
|
||||
if (ch === '>') {
|
||||
for(var i=0; i < sel.length; i++) {
|
||||
if (sel[i][0] === '>') {
|
||||
ch = '>';
|
||||
} else {
|
||||
ch = '> ';
|
||||
}
|
||||
sel[i] = ch + sel[i];
|
||||
}
|
||||
return sel.join('\n');
|
||||
}
|
||||
|
||||
return sel.join('\n' + ch);
|
||||
}
|
||||
|
||||
function assist(area, action, root) {
|
||||
|
@ -141,9 +153,9 @@ JX.behavior('phabricator-remarkup-assist', function(config) {
|
|||
update(area, code_prefix + '```\n', sel, '\n```');
|
||||
break;
|
||||
case 'fa-quote-right':
|
||||
ch = '> ';
|
||||
ch = '>';
|
||||
sel = prepend_char_to_lines(ch, sel, pht('Quoted Text'));
|
||||
update(area, ((r.start === 0) ? '' : '\n\n') + ch, sel, '\n\n');
|
||||
update(area, ((r.start === 0) ? '' : '\n\n'), sel, '\n\n');
|
||||
break;
|
||||
case 'fa-table':
|
||||
var table_prefix = (r.start === 0 ? '' : '\n\n');
|
||||
|
|
Loading…
Reference in a new issue