Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2894229
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Advanced/Developer...
View Handle
View Hovercard
Size
24 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/applications/diffusion/query/pathid/DiffusionPathIDQuery.php b/src/applications/diffusion/query/pathid/DiffusionPathIDQuery.php
index a36c0da816..7c9e721431 100644
--- a/src/applications/diffusion/query/pathid/DiffusionPathIDQuery.php
+++ b/src/applications/diffusion/query/pathid/DiffusionPathIDQuery.php
@@ -1,94 +1,96 @@
<?php
/**
* @task pathutil Path Utilities
*/
final class DiffusionPathIDQuery extends Phobject {
+ private $paths = array();
+
public function __construct(array $paths) {
$this->paths = $paths;
}
public function loadPathIDs() {
$repository = new PhabricatorRepository();
$path_normal_map = array();
foreach ($this->paths as $path) {
$normal = self::normalizePath($path);
$path_normal_map[$normal][] = $path;
}
$paths = queryfx_all(
$repository->establishConnection('r'),
'SELECT * FROM %T WHERE pathHash IN (%Ls)',
PhabricatorRepository::TABLE_PATH,
array_map('md5', array_keys($path_normal_map)));
$paths = ipull($paths, 'id', 'path');
$result = array();
foreach ($path_normal_map as $normal => $originals) {
foreach ($originals as $original) {
$result[$original] = idx($paths, $normal);
}
}
return $result;
}
/**
* Convert a path to the canonical, absolute representation used by Diffusion.
*
* @param string Some repository path.
* @return string Canonicalized Diffusion path.
* @task pathutil
*/
public static function normalizePath($path) {
// Normalize to single slashes, e.g. "///" => "/".
$path = preg_replace('@[/]{2,}@', '/', $path);
return '/'.trim($path, '/');
}
/**
* Return the canonical parent directory for a path. Note, returns "/" when
* passed "/".
*
* @param string Some repository path.
* @return string That path's canonical parent directory.
* @task pathutil
*/
public static function getParentPath($path) {
$path = self::normalizePath($path);
$path = dirname($path);
if (phutil_is_windows() && $path == '\\') {
$path = '/';
}
return $path;
}
/**
* Generate a list of parents for a repository path. The path itself is
* included.
*
* @param string Some repository path.
* @return list List of canonical paths between the path and the root.
* @task pathutil
*/
public static function expandPathToRoot($path) {
$path = self::normalizePath($path);
$parents = array($path);
$parts = explode('/', trim($path, '/'));
while (count($parts) >= 1) {
if (array_pop($parts)) {
$parents[] = '/'.implode('/', $parts);
}
}
return $parents;
}
}
diff --git a/src/applications/feed/builder/PhabricatorFeedBuilder.php b/src/applications/feed/builder/PhabricatorFeedBuilder.php
index d4aa23b38b..898f2aa6f7 100644
--- a/src/applications/feed/builder/PhabricatorFeedBuilder.php
+++ b/src/applications/feed/builder/PhabricatorFeedBuilder.php
@@ -1,103 +1,104 @@
<?php
final class PhabricatorFeedBuilder extends Phobject {
+ private $user;
private $stories;
private $framed;
private $hovercards = false;
private $noDataString;
public function __construct(array $stories) {
assert_instances_of($stories, 'PhabricatorFeedStory');
$this->stories = $stories;
}
public function setFramed($framed) {
$this->framed = $framed;
return $this;
}
public function setUser(PhabricatorUser $user) {
$this->user = $user;
return $this;
}
public function setShowHovercards($hover) {
$this->hovercards = $hover;
return $this;
}
public function setNoDataString($string) {
$this->noDataString = $string;
return $this;
}
public function buildView() {
if (!$this->user) {
throw new PhutilInvalidStateException('setUser');
}
$user = $this->user;
$stories = $this->stories;
$null_view = new AphrontNullView();
require_celerity_resource('phabricator-feed-css');
$last_date = null;
foreach ($stories as $story) {
$story->setFramed($this->framed);
$story->setHovercard($this->hovercards);
$date = ucfirst(phabricator_relative_date($story->getEpoch(), $user));
if ($date !== $last_date) {
if ($last_date !== null) {
$null_view->appendChild(
phutil_tag_div('phabricator-feed-story-date-separator'));
}
$last_date = $date;
$header = new PHUIActionHeaderView();
$header->setHeaderTitle($date);
$null_view->appendChild($header);
}
try {
$view = $story->renderView();
$view->setUser($user);
$view = $view->render();
} catch (Exception $ex) {
// If rendering failed for any reason, don't fail the entire feed,
// just this one story.
$view = id(new PHUIFeedStoryView())
->setUser($user)
->setChronologicalKey($story->getChronologicalKey())
->setEpoch($story->getEpoch())
->setTitle(
pht('Feed Story Failed to Render (%s)', get_class($story)))
->appendChild(pht('%s: %s', get_class($ex), $ex->getMessage()));
}
$null_view->appendChild($view);
}
if (empty($stories)) {
$nodatastring = pht('No Stories.');
if ($this->noDataString) {
$nodatastring = $this->noDataString;
}
$view = id(new PHUIInfoView())
->setSeverity(PHUIInfoView::SEVERITY_NODATA)
->appendChild($nodatastring);
$null_view->appendChild($view);
}
return id(new AphrontNullView())
->appendChild($null_view->render());
}
}
diff --git a/src/applications/herald/adapter/HeraldDifferentialRevisionAdapter.php b/src/applications/herald/adapter/HeraldDifferentialRevisionAdapter.php
index afd328b342..a731254870 100644
--- a/src/applications/herald/adapter/HeraldDifferentialRevisionAdapter.php
+++ b/src/applications/herald/adapter/HeraldDifferentialRevisionAdapter.php
@@ -1,321 +1,322 @@
<?php
final class HeraldDifferentialRevisionAdapter
extends HeraldDifferentialAdapter {
+ protected $diff;
protected $revision;
protected $explicitReviewers;
protected $addReviewerPHIDs = array();
protected $blockingReviewerPHIDs = array();
protected $buildPlans = array();
protected $requiredSignatureDocumentPHIDs = array();
protected $affectedPackages;
protected $changesets;
private $haveHunks;
public function getAdapterApplicationClass() {
return 'PhabricatorDifferentialApplication';
}
protected function newObject() {
return new DifferentialRevision();
}
public function getObject() {
return $this->revision;
}
public function getDiff() {
return $this->diff;
}
public function getAdapterContentType() {
return 'differential';
}
public function getAdapterContentName() {
return pht('Differential Revisions');
}
public function getAdapterContentDescription() {
return pht(
"React to revisions being created or updated.\n".
"Revision rules can send email, flag revisions, add reviewers, ".
"and run build plans.");
}
public function supportsRuleType($rule_type) {
switch ($rule_type) {
case HeraldRuleTypeConfig::RULE_TYPE_GLOBAL:
case HeraldRuleTypeConfig::RULE_TYPE_PERSONAL:
return true;
case HeraldRuleTypeConfig::RULE_TYPE_OBJECT:
default:
return false;
}
}
public function getFields() {
return array_merge(
array(
self::FIELD_TITLE,
self::FIELD_BODY,
self::FIELD_AUTHOR,
self::FIELD_AUTHOR_PROJECTS,
self::FIELD_REVIEWERS,
self::FIELD_CC,
self::FIELD_REPOSITORY,
self::FIELD_REPOSITORY_PROJECTS,
self::FIELD_DIFF_FILE,
self::FIELD_DIFF_CONTENT,
self::FIELD_DIFF_ADDED_CONTENT,
self::FIELD_DIFF_REMOVED_CONTENT,
self::FIELD_AFFECTED_PACKAGE,
self::FIELD_AFFECTED_PACKAGE_OWNER,
self::FIELD_IS_NEW_OBJECT,
),
parent::getFields());
}
public function getRepetitionOptions() {
return array(
HeraldRepetitionPolicyConfig::EVERY,
HeraldRepetitionPolicyConfig::FIRST,
);
}
public static function newLegacyAdapter(
DifferentialRevision $revision,
DifferentialDiff $diff) {
$object = new HeraldDifferentialRevisionAdapter();
// Reload the revision to pick up relationship information.
$revision = id(new DifferentialRevisionQuery())
->withIDs(array($revision->getID()))
->setViewer(PhabricatorUser::getOmnipotentUser())
->needRelationships(true)
->needReviewerStatus(true)
->executeOne();
$object->revision = $revision;
$object->diff = $diff;
return $object;
}
public function setExplicitReviewers($explicit_reviewers) {
$this->explicitReviewers = $explicit_reviewers;
return $this;
}
public function getReviewersAddedByHerald() {
return $this->addReviewerPHIDs;
}
public function getBlockingReviewersAddedByHerald() {
return $this->blockingReviewerPHIDs;
}
public function getRequiredSignatureDocumentPHIDs() {
return $this->requiredSignatureDocumentPHIDs;
}
public function getBuildPlans() {
return $this->buildPlans;
}
public function getPHID() {
return $this->revision->getPHID();
}
public function getHeraldName() {
return $this->revision->getTitle();
}
protected function loadChangesets() {
if ($this->changesets === null) {
$this->changesets = $this->diff->loadChangesets();
}
return $this->changesets;
}
protected function loadChangesetsWithHunks() {
$changesets = $this->loadChangesets();
if ($changesets && !$this->haveHunks) {
$this->haveHunks = true;
id(new DifferentialHunkQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withChangesets($changesets)
->needAttachToChangesets(true)
->execute();
}
return $changesets;
}
public function loadAffectedPackages() {
if ($this->affectedPackages === null) {
$this->affectedPackages = array();
$repository = $this->loadRepository();
if ($repository) {
$packages = PhabricatorOwnersPackage::loadAffectedPackages(
$repository,
$this->loadAffectedPaths());
$this->affectedPackages = $packages;
}
}
return $this->affectedPackages;
}
public function getHeraldField($field) {
switch ($field) {
case self::FIELD_TITLE:
return $this->revision->getTitle();
break;
case self::FIELD_BODY:
return $this->revision->getSummary()."\n".
$this->revision->getTestPlan();
break;
case self::FIELD_AUTHOR:
return $this->revision->getAuthorPHID();
break;
case self::FIELD_AUTHOR_PROJECTS:
$author_phid = $this->revision->getAuthorPHID();
if (!$author_phid) {
return array();
}
$projects = id(new PhabricatorProjectQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withMemberPHIDs(array($author_phid))
->execute();
return mpull($projects, 'getPHID');
case self::FIELD_DIFF_FILE:
return $this->loadAffectedPaths();
case self::FIELD_REVIEWERS:
if (isset($this->explicitReviewers)) {
return array_keys($this->explicitReviewers);
} else {
return $this->revision->getReviewers();
}
case self::FIELD_REPOSITORY:
$repository = $this->loadRepository();
if (!$repository) {
return null;
}
return $repository->getPHID();
case self::FIELD_REPOSITORY_PROJECTS:
$repository = $this->loadRepository();
if (!$repository) {
return array();
}
return $repository->getProjectPHIDs();
case self::FIELD_DIFF_CONTENT:
return $this->loadContentDictionary();
case self::FIELD_DIFF_ADDED_CONTENT:
return $this->loadAddedContentDictionary();
case self::FIELD_DIFF_REMOVED_CONTENT:
return $this->loadRemovedContentDictionary();
case self::FIELD_AFFECTED_PACKAGE:
$packages = $this->loadAffectedPackages();
return mpull($packages, 'getPHID');
case self::FIELD_AFFECTED_PACKAGE_OWNER:
$packages = $this->loadAffectedPackages();
return PhabricatorOwnersOwner::loadAffiliatedUserPHIDs(
mpull($packages, 'getID'));
}
return parent::getHeraldField($field);
}
public function getActions($rule_type) {
switch ($rule_type) {
case HeraldRuleTypeConfig::RULE_TYPE_GLOBAL:
return array_merge(
array(
self::ACTION_ADD_CC,
self::ACTION_REMOVE_CC,
self::ACTION_EMAIL,
self::ACTION_ADD_REVIEWERS,
self::ACTION_ADD_BLOCKING_REVIEWERS,
self::ACTION_APPLY_BUILD_PLANS,
self::ACTION_REQUIRE_SIGNATURE,
self::ACTION_NOTHING,
),
parent::getActions($rule_type));
case HeraldRuleTypeConfig::RULE_TYPE_PERSONAL:
return array_merge(
array(
self::ACTION_ADD_CC,
self::ACTION_REMOVE_CC,
self::ACTION_EMAIL,
self::ACTION_FLAG,
self::ACTION_ADD_REVIEWERS,
self::ACTION_ADD_BLOCKING_REVIEWERS,
self::ACTION_NOTHING,
),
parent::getActions($rule_type));
}
}
public function applyHeraldEffects(array $effects) {
assert_instances_of($effects, 'HeraldEffect');
$result = array();
foreach ($effects as $effect) {
$action = $effect->getAction();
switch ($action) {
case self::ACTION_ADD_REVIEWERS:
foreach ($effect->getTarget() as $phid) {
$this->addReviewerPHIDs[$phid] = true;
}
$result[] = new HeraldApplyTranscript(
$effect,
true,
pht('Added reviewers.'));
break;
case self::ACTION_ADD_BLOCKING_REVIEWERS:
// This adds reviewers normally, it just also marks them blocking.
foreach ($effect->getTarget() as $phid) {
$this->addReviewerPHIDs[$phid] = true;
$this->blockingReviewerPHIDs[$phid] = true;
}
$result[] = new HeraldApplyTranscript(
$effect,
true,
pht('Added blocking reviewers.'));
break;
case self::ACTION_APPLY_BUILD_PLANS:
foreach ($effect->getTarget() as $phid) {
$this->buildPlans[] = $phid;
}
$result[] = new HeraldApplyTranscript(
$effect,
true,
pht('Applied build plans.'));
break;
case self::ACTION_REQUIRE_SIGNATURE:
foreach ($effect->getTarget() as $phid) {
$this->requiredSignatureDocumentPHIDs[] = $phid;
}
$result[] = new HeraldApplyTranscript(
$effect,
true,
pht('Required signatures.'));
break;
default:
$result[] = $this->applyStandardEffect($effect);
break;
}
}
return $result;
}
}
diff --git a/src/applications/metamta/adapter/PhabricatorMailImplementationPHPMailerLiteAdapter.php b/src/applications/metamta/adapter/PhabricatorMailImplementationPHPMailerLiteAdapter.php
index e758832039..2a8b12b64a 100644
--- a/src/applications/metamta/adapter/PhabricatorMailImplementationPHPMailerLiteAdapter.php
+++ b/src/applications/metamta/adapter/PhabricatorMailImplementationPHPMailerLiteAdapter.php
@@ -1,105 +1,107 @@
<?php
/**
* TODO: Should be final, but inherited by SES.
*/
class PhabricatorMailImplementationPHPMailerLiteAdapter
extends PhabricatorMailImplementationAdapter {
+ protected $mailer;
+
/**
* @phutil-external-symbol class PHPMailerLite
*/
public function __construct() {
$root = phutil_get_library_root('phabricator');
$root = dirname($root);
require_once $root.'/externals/phpmailer/class.phpmailer-lite.php';
$this->mailer = new PHPMailerLite($use_exceptions = true);
$this->mailer->CharSet = 'utf-8';
$encoding = PhabricatorEnv::getEnvConfig('phpmailer.smtp-encoding', '8bit');
$this->mailer->Encoding = $encoding;
// By default, PHPMailerLite sends one mail per recipient. We handle
// multiplexing higher in the stack, so tell it to send mail exactly
// like we ask.
$this->mailer->SingleTo = false;
}
public function supportsMessageIDHeader() {
return true;
}
public function setFrom($email, $name = '') {
$this->mailer->SetFrom($email, $name, $crazy_side_effects = false);
return $this;
}
public function addReplyTo($email, $name = '') {
$this->mailer->AddReplyTo($email, $name);
return $this;
}
public function addTos(array $emails) {
foreach ($emails as $email) {
$this->mailer->AddAddress($email);
}
return $this;
}
public function addCCs(array $emails) {
foreach ($emails as $email) {
$this->mailer->AddCC($email);
}
return $this;
}
public function addAttachment($data, $filename, $mimetype) {
$this->mailer->AddStringAttachment(
$data,
$filename,
'base64',
$mimetype);
return $this;
}
public function addHeader($header_name, $header_value) {
if (strtolower($header_name) == 'message-id') {
$this->mailer->MessageID = $header_value;
} else {
$this->mailer->AddCustomHeader($header_name.': '.$header_value);
}
return $this;
}
public function setBody($body) {
$this->mailer->Body = $body;
$this->mailer->IsHTML(false);
return $this;
}
/**
* Note: phpmailer-lite does NOT support sending messages with mixed version
* (plaintext and html). So for now lets just use HTML if it's available.
* @param $html
*/
public function setHTMLBody($html_body) {
$this->mailer->Body = $html_body;
$this->mailer->IsHTML(true);
return $this;
}
public function setSubject($subject) {
$this->mailer->Subject = $subject;
return $this;
}
public function hasValidRecipients() {
return true;
}
public function send() {
return $this->mailer->Send();
}
}
diff --git a/src/applications/releeph/view/branch/ReleephBranchTemplate.php b/src/applications/releeph/view/branch/ReleephBranchTemplate.php
index 2441d924c1..d1564c55bb 100644
--- a/src/applications/releeph/view/branch/ReleephBranchTemplate.php
+++ b/src/applications/releeph/view/branch/ReleephBranchTemplate.php
@@ -1,195 +1,200 @@
<?php
final class ReleephBranchTemplate extends Phobject {
const KEY = 'releeph.default-branch-template';
+ private $commitHandle;
+ private $branchDate;
+ private $projectName;
+ private $isSymbolic;
+
public static function getDefaultTemplate() {
return PhabricatorEnv::getEnvConfig(self::KEY);
}
public static function getRequiredDefaultTemplate() {
$template = self::getDefaultTemplate();
if (!$template) {
throw new Exception(pht(
"Config setting '%s' must be set, ".
"or you must provide a branch-template for each project!",
self::KEY));
}
return $template;
}
public static function getFakeCommitHandleFor(
$repository_phid,
PhabricatorUser $viewer) {
$repository = id(new PhabricatorRepositoryQuery())
->setViewer($viewer)
->withPHIDs(array($repository_phid))
->executeOne();
$fake_handle = 'SOFAKE';
if ($repository) {
$fake_handle = id(new PhabricatorObjectHandle())
->setName($repository->formatCommitName('100000000000'));
}
return $fake_handle;
}
private $commitHandle;
private $branchDate = null;
private $projectName;
private $isSymbolic;
public function setCommitHandle(PhabricatorObjectHandle $handle) {
$this->commitHandle = $handle;
return $this;
}
public function setBranchDate($branch_date) {
$this->branchDate = $branch_date;
return $this;
}
public function setReleephProjectName($project_name) {
$this->projectName = $project_name;
return $this;
}
public function setSymbolic($is_symbolic) {
$this->isSymbolic = $is_symbolic;
return $this;
}
public function interpolate($template) {
if (!$this->projectName) {
return array('', array());
}
list($name, $name_errors) = $this->interpolateInner(
$template,
$this->isSymbolic);
if ($this->isSymbolic) {
return array($name, $name_errors);
} else {
$validate_errors = $this->validateAsBranchName($name);
$errors = array_merge($name_errors, $validate_errors);
return array($name, $errors);
}
}
/*
* xsprintf() would be useful here, but that's for formatting concrete lists
* of things in a certain way...
*
* animal_printf('%A %A %A', $dog1, $dog2, $dog3);
*
* ...rather than interpolating percent-control-strings like strftime does.
*/
private function interpolateInner($template, $is_symbolic) {
$name = $template;
$errors = array();
$safe_project_name = str_replace(' ', '-', $this->projectName);
$short_commit_id = last(
preg_split('/r[A-Z]+/', $this->commitHandle->getName()));
$interpolations = array();
for ($ii = 0; $ii < strlen($name); $ii++) {
$char = substr($name, $ii, 1);
$prev = null;
if ($ii > 0) {
$prev = substr($name, $ii - 1, 1);
}
$next = substr($name, $ii + 1, 1);
if ($next && $char == '%' && $prev != '%') {
$interpolations[$ii] = $next;
}
}
$variable_interpolations = array();
$reverse_interpolations = $interpolations;
krsort($reverse_interpolations);
if ($this->branchDate) {
$branch_date = $this->branchDate;
} else {
$branch_date = $this->commitHandle->getTimestamp();
}
foreach ($reverse_interpolations as $position => $code) {
$replacement = null;
switch ($code) {
case 'v':
$replacement = $this->commitHandle->getName();
$is_variable = true;
break;
case 'V':
$replacement = $short_commit_id;
$is_variable = true;
break;
case 'P':
$replacement = $safe_project_name;
$is_variable = false;
break;
case 'p':
$replacement = strtolower($safe_project_name);
$is_variable = false;
break;
default:
// Format anything else using strftime()
$replacement = strftime("%{$code}", $branch_date);
$is_variable = true;
break;
}
if ($is_variable) {
$variable_interpolations[] = $code;
}
$name = substr_replace($name, $replacement, $position, 2);
}
if (!$is_symbolic && !$variable_interpolations) {
$errors[] = pht("Include additional interpolations that aren't static!");
}
return array($name, $errors);
}
private function validateAsBranchName($name) {
$errors = array();
if (preg_match('{^/}', $name) || preg_match('{/$}', $name)) {
$errors[] = pht("Branches cannot begin or end with '%s'", '/');
}
if (preg_match('{//+}', $name)) {
$errors[] = pht("Branches cannot contain multiple consecutive '%s'", '/');
}
$parts = array_filter(explode('/', $name));
foreach ($parts as $index => $part) {
$part_error = null;
if (preg_match('{^\.}', $part) || preg_match('{\.$}', $part)) {
$errors[] = pht("Path components cannot begin or end with '%s'", '.');
} else if (preg_match('{^(?!\w)}', $part)) {
$errors[] = pht('Path components must begin with an alphanumeric.');
} else if (!preg_match('{^\w ([\w-_%\.]* [\w-_%])?$}x', $part)) {
$errors[] = pht(
"Path components may only contain alphanumerics ".
"or '%s', '%s' or '%s'.",
'-',
'_',
'.');
}
}
return $errors;
}
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Jan 19 2025, 19:36 (6 w, 2 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1128033
Default Alt Text
(24 KB)
Attached To
Mode
rP Phorge
Attached
Detach File
Event Timeline
Log In to Comment