Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/config/check/PhabricatorManualActivitySetupCheck.php b/src/applications/config/check/PhabricatorManualActivitySetupCheck.php
index c5c756e49b..04457cb12a 100644
--- a/src/applications/config/check/PhabricatorManualActivitySetupCheck.php
+++ b/src/applications/config/check/PhabricatorManualActivitySetupCheck.php
@@ -1,146 +1,147 @@
<?php
final class PhabricatorManualActivitySetupCheck
extends PhabricatorSetupCheck {
public function getDefaultGroup() {
return self::GROUP_OTHER;
}
protected function executeChecks() {
$activities = id(new PhabricatorConfigManualActivity())->loadAll();
foreach ($activities as $activity) {
$type = $activity->getActivityType();
switch ($type) {
case PhabricatorConfigManualActivity::TYPE_REINDEX:
$this->raiseSearchReindexIssue();
break;
case PhabricatorConfigManualActivity::TYPE_IDENTITIES:
$this->raiseRebuildIdentitiesIssue();
break;
default:
}
}
}
private function raiseSearchReindexIssue() {
$activity_name = pht('Rebuild Search Index');
$activity_summary = pht(
'The search index algorithm has been updated and the index needs '.
'be rebuilt.');
$message = array();
$message[] = pht(
'The indexing algorithm for the fulltext search index has been '.
'updated and the index needs to be rebuilt. Until you rebuild the '.
'index, global search (and other fulltext search) will not '.
'function correctly.');
$message[] = pht(
'You can rebuild the search index while Phabricator is running.');
$message[] = pht(
'To rebuild the index, run this command:');
$message[] = phutil_tag(
'pre',
array(),
(string)csprintf(
'phabricator/ $ ./bin/search index --all --force --background'));
$message[] = pht(
'You can find more information about rebuilding the search '.
'index here: %s',
phutil_tag(
'a',
array(
'href' => 'https://phurl.io/u/reindex',
'target' => '_blank',
),
'https://phurl.io/u/reindex'));
$message[] = pht(
'After rebuilding the index, run this command to clear this setup '.
'warning:');
$message[] = phutil_tag(
'pre',
array(),
'phabricator/ $ ./bin/config done reindex');
$activity_message = phutil_implode_html("\n\n", $message);
$this->newIssue('manual.reindex')
->setName($activity_name)
->setSummary($activity_summary)
->setMessage($activity_message);
}
private function raiseRebuildIdentitiesIssue() {
$activity_name = pht('Rebuild Repository Identities');
$activity_summary = pht(
'The mapping from VCS users to Phabricator users has changed '.
'and must be rebuilt.');
$message = array();
$message[] = pht(
'The way Phabricator attributes VCS activity to Phabricator users '.
'has changed. There is a new indirection layer between the strings '.
'that appear as VCS authors and committers (such as "John Developer '.
'<johnd@bigcorp.com>") and the Phabricator user that gets associated '.
'with VCS commits. This is to support situations where users '.
'are incorrectly associated with commits by Phabricator making bad '.
'guesses about the identity of the corresponding Phabricator user. '.
'This also helps with situations where existing repositories are '.
'imported without having created accounts for all the committers to '.
'that repository. Until you rebuild these repository identities, you '.
'are likely to encounter problems with future Phabricator features '.
'which will rely on the existence of these identities.');
$message[] = pht(
'You can rebuild repository identities while Phabricator is running.');
$message[] = pht(
'To rebuild identities, run this command:');
$message[] = phutil_tag(
'pre',
array(),
(string)csprintf(
- 'phabricator/ $ ./bin/repository rebuild-identities --all'));
+ 'phabricator/ $ '.
+ './bin/repository rebuild-identities --all-repositories'));
$message[] = pht(
'You can find more information about this new identity mapping '.
'here: %s',
phutil_tag(
'a',
array(
'href' => 'https://phurl.io/u/repoIdentities',
'target' => '_blank',
),
'https://phurl.io/u/repoIdentities'));
$message[] = pht(
'After rebuilding repository identities, run this command to clear '.
'this setup warning:');
$message[] = phutil_tag(
'pre',
array(),
'phabricator/ $ ./bin/config done identities');
$activity_message = phutil_implode_html("\n\n", $message);
$this->newIssue('manual.identities')
->setName($activity_name)
->setSummary($activity_summary)
->setMessage($activity_message);
}
}
diff --git a/src/applications/diffusion/identity/DiffusionRepositoryIdentityEngine.php b/src/applications/diffusion/identity/DiffusionRepositoryIdentityEngine.php
index 5d71996622..635622fda2 100644
--- a/src/applications/diffusion/identity/DiffusionRepositoryIdentityEngine.php
+++ b/src/applications/diffusion/identity/DiffusionRepositoryIdentityEngine.php
@@ -1,80 +1,98 @@
<?php
final class DiffusionRepositoryIdentityEngine
extends Phobject {
private $viewer;
private $sourcePHID;
public function setViewer(PhabricatorUser $viewer) {
$this->viewer = $viewer;
return $this;
}
public function getViewer() {
return $this->viewer;
}
public function setSourcePHID($source_phid) {
$this->sourcePHID = $source_phid;
return $this;
}
public function getSourcePHID() {
if (!$this->sourcePHID) {
throw new PhutilInvalidStateException('setSourcePHID');
}
return $this->sourcePHID;
}
public function newResolvedIdentity($raw_identity) {
$identity = $this->loadRawIdentity($raw_identity);
if (!$identity) {
$identity = $this->newIdentity($raw_identity);
}
return $this->updateIdentity($identity);
}
public function newUpdatedIdentity(PhabricatorRepositoryIdentity $identity) {
return $this->updateIdentity($identity);
}
private function loadRawIdentity($raw_identity) {
$viewer = $this->getViewer();
return id(new PhabricatorRepositoryIdentityQuery())
->setViewer($viewer)
->withIdentityNames(array($raw_identity))
->executeOne();
}
private function newIdentity($raw_identity) {
$source_phid = $this->getSourcePHID();
return id(new PhabricatorRepositoryIdentity())
->setAuthorPHID($source_phid)
->setIdentityName($raw_identity);
}
private function resolveIdentity(PhabricatorRepositoryIdentity $identity) {
$raw_identity = $identity->getIdentityName();
return id(new DiffusionResolveUserQuery())
->withName($raw_identity)
->execute();
}
private function updateIdentity(PhabricatorRepositoryIdentity $identity) {
+
+ // If we're updating an identity and it has a manual user PHID associated
+ // with it but the user is no longer valid, remove the value. This likely
+ // corresponds to a user that was destroyed.
+
+ $assigned_phid = $identity->getManuallySetUserPHID();
+ $unassigned = DiffusionIdentityUnassignedDatasource::FUNCTION_TOKEN;
+ if ($assigned_phid && ($assigned_phid !== $unassigned)) {
+ $viewer = $this->getViewer();
+ $user = id(new PhabricatorPeopleQuery())
+ ->setViewer($viewer)
+ ->withPHIDs(array($assigned_phid))
+ ->executeOne();
+ if (!$user) {
+ $identity->setManuallySetUserPHID(null);
+ }
+ }
+
$resolved_phid = $this->resolveIdentity($identity);
$identity
->setAutomaticGuessedUserPHID($resolved_phid)
->save();
return $identity;
}
}
diff --git a/src/applications/repository/management/PhabricatorRepositoryManagementRebuildIdentitiesWorkflow.php b/src/applications/repository/management/PhabricatorRepositoryManagementRebuildIdentitiesWorkflow.php
index 77ba5b55b0..c1f92e8371 100644
--- a/src/applications/repository/management/PhabricatorRepositoryManagementRebuildIdentitiesWorkflow.php
+++ b/src/applications/repository/management/PhabricatorRepositoryManagementRebuildIdentitiesWorkflow.php
@@ -1,116 +1,383 @@
<?php
final class PhabricatorRepositoryManagementRebuildIdentitiesWorkflow
extends PhabricatorRepositoryManagementWorkflow {
private $identityCache = array();
protected function didConstruct() {
$this
->setName('rebuild-identities')
->setExamples(
'**rebuild-identities** [__options__] __repository__')
->setSynopsis(pht('Rebuild repository identities from commits.'))
->setArguments(
array(
array(
- 'name' => 'repositories',
- 'wildcard' => true,
+ 'name' => 'all-repositories',
+ 'help' => pht('Rebuild identities across all repositories.'),
),
array(
- 'name' => 'all',
- 'help' => pht('Rebuild identities across all repositories.'),
- ),
+ 'name' => 'all-identities',
+ 'help' => pht('Rebuild all currently-known identities.'),
+ ),
+ array(
+ 'name' => 'repository',
+ 'param' => 'repository',
+ 'repeat' => true,
+ 'help' => pht('Rebuild identities in a repository.'),
+ ),
+ array(
+ 'name' => 'commit',
+ 'param' => 'commit',
+ 'repeat' => true,
+ 'help' => pht('Rebuild identities for a commit.'),
+ ),
+ array(
+ 'name' => 'user',
+ 'param' => 'user',
+ 'repeat' => true,
+ 'help' => pht('Rebuild identities for a user.'),
+ ),
+ array(
+ 'name' => 'email',
+ 'param' => 'email',
+ 'repeat' => true,
+ 'help' => pht('Rebuild identities for an email address.'),
+ ),
+ array(
+ 'name' => 'raw',
+ 'param' => 'raw',
+ 'repeat' => true,
+ 'help' => pht('Rebuild identities for a raw commit string.'),
+ ),
));
}
public function execute(PhutilArgumentParser $args) {
- $console = PhutilConsole::getConsole();
+ $viewer = $this->getViewer();
+
+ $rebuilt_anything = false;
- $all = $args->getArg('all');
- $repositories = $args->getArg('repositories');
- if ($all xor empty($repositories)) {
+ $all_repositories = $args->getArg('all-repositories');
+ $repositories = $args->getArg('repository');
+
+ if ($all_repositories && $repositories) {
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'Flags "--all-repositories" and "--repository" are not '.
+ 'compatible.'));
+ }
+
+
+ $all_identities = $args->getArg('all-identities');
+ $raw = $args->getArg('raw');
+
+ if ($all_identities && $raw) {
throw new PhutilArgumentUsageException(
- pht('Specify --all or a list of repositories, but not both.'));
+ pht(
+ 'Flags "--all-identities" and "--raw" are not '.
+ 'compatible.'));
}
- $query = id(new DiffusionCommitQuery())
- ->setViewer(PhabricatorUser::getOmnipotentUser())
- ->needCommitData(true);
+ if ($all_repositories || $repositories) {
+ $rebuilt_anything = true;
- if ($repositories) {
- $repos = $this->loadRepositories($args, 'repositories');
- $query->withRepositoryIDs(mpull($repos, 'getID'));
+ if ($repositories) {
+ $repository_list = $this->loadRepositories($args, 'repository');
+ } else {
+ $repository_query = id(new PhabricatorRepositoryQuery())
+ ->setViewer($viewer);
+ $repository_list = new PhabricatorQueryIterator($repository_query);
+ }
+
+ foreach ($repository_list as $repository) {
+ $commit_query = id(new DiffusionCommitQuery())
+ ->setViewer($viewer)
+ ->needCommitData(true)
+ ->withRepositoryIDs(array($repository->getID()));
+
+ $commit_iterator = new PhabricatorQueryIterator($commit_query);
+
+ $this->rebuildCommits($commit_iterator);
+ }
+ }
+
+ $commits = $args->getArg('commit');
+ if ($commits) {
+ $rebuilt_anything = true;
+ $commit_list = $this->loadCommits($args, 'commit');
+
+ // Reload commits to get commit data.
+ $commit_list = id(new DiffusionCommitQuery())
+ ->setViewer($viewer)
+ ->needCommitData(true)
+ ->withIDs(mpull($commit_list, 'getID'))
+ ->execute();
+
+ $this->rebuildCommits($commit_list);
+ }
+
+ $users = $args->getArg('user');
+ if ($users) {
+ $rebuilt_anything = true;
+
+ $user_list = $this->loadUsersFromArguments($users);
+ $this->rebuildUsers($user_list);
+ }
+
+ $emails = $args->getArg('email');
+ if ($emails) {
+ $rebuilt_anything = true;
+ $this->rebuildEmails($emails);
+ }
+
+ if ($all_identities || $raw) {
+ $rebuilt_anything = true;
+
+ if ($raw) {
+ $identities = id(new PhabricatorRepositoryIdentityQuery())
+ ->setViewer($viewer)
+ ->withIdentityNames($raw)
+ ->execute();
+
+ $identities = mpull($identities, null, 'getIdentityNameRaw');
+ foreach ($raw as $raw_identity) {
+ if (!isset($identities[$raw_identity])) {
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'No identity "%s" exists. When selecting identities with '.
+ '"--raw", the entire identity must match exactly.',
+ $raw_identity));
+ }
+ }
+
+ $identity_list = $identities;
+ } else {
+ $identity_query = id(new PhabricatorRepositoryIdentityQuery())
+ ->setViewer($viewer);
+
+ $identity_list = new PhabricatorQueryIterator($identity_query);
+
+ $this->logInfo(
+ pht('REBUILD'),
+ pht('Rebuilding all existing identities.'));
+ }
+
+ $this->rebuildIdentities($identity_list);
+ }
+
+ if (!$rebuilt_anything) {
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'Nothing specified to rebuild. Use flags to choose which '.
+ 'identities to rebuild, or "--help" for help.'));
}
- $iterator = new PhabricatorQueryIterator($query);
- foreach ($iterator as $commit) {
+ return 0;
+ }
+
+ private function rebuildCommits($commits) {
+ foreach ($commits as $commit) {
$needs_update = false;
$data = $commit->getCommitData();
$author_name = $data->getAuthorName();
$author_identity = $this->getIdentityForCommit(
$commit,
$author_name);
$author_phid = $commit->getAuthorIdentityPHID();
$identity_phid = $author_identity->getPHID();
+
+ $aidentity_phid = $identity_phid;
if ($author_phid !== $identity_phid) {
$commit->setAuthorIdentityPHID($identity_phid);
$data->setCommitDetail('authorIdentityPHID', $identity_phid);
$needs_update = true;
}
$committer_name = $data->getCommitDetail('committer', null);
$committer_phid = $commit->getCommitterIdentityPHID();
if (strlen($committer_name)) {
$committer_identity = $this->getIdentityForCommit(
$commit,
$committer_name);
$identity_phid = $committer_identity->getPHID();
} else {
$identity_phid = null;
}
if ($committer_phid !== $identity_phid) {
$commit->setCommitterIdentityPHID($identity_phid);
$data->setCommitDetail('committerIdentityPHID', $identity_phid);
$needs_update = true;
}
if ($needs_update) {
$commit->save();
$data->save();
- echo tsprintf(
- "Rebuilt identities for %s.\n",
- $commit->getDisplayName());
+
+ $this->logInfo(
+ pht('COMMIT'),
+ pht(
+ 'Rebuilt identities for "%s".',
+ $commit->getDisplayName()));
} else {
- echo tsprintf(
- "No changes for %s.\n",
- $commit->getDisplayName());
+ $this->logInfo(
+ pht('SKIP'),
+ pht(
+ 'No changes for commit "%s".',
+ $commit->getDisplayName()));
}
}
-
}
private function getIdentityForCommit(
PhabricatorRepositoryCommit $commit,
$raw_identity) {
if (!isset($this->identityCache[$raw_identity])) {
$viewer = $this->getViewer();
$identity = id(new DiffusionRepositoryIdentityEngine())
->setViewer($viewer)
->setSourcePHID($commit->getPHID())
->newResolvedIdentity($raw_identity);
$this->identityCache[$raw_identity] = $identity;
}
return $this->identityCache[$raw_identity];
}
+
+ private function rebuildUsers($users) {
+ $viewer = $this->getViewer();
+
+ foreach ($users as $user) {
+ $this->logInfo(
+ pht('USER'),
+ pht(
+ 'Rebuilding identities for user "%s".',
+ $user->getMonogram()));
+
+ $emails = id(new PhabricatorUserEmail())->loadAllWhere(
+ 'userPHID = %s',
+ $user->getPHID());
+ if ($emails) {
+ $this->rebuildEmails(mpull($emails, 'getAddress'));
+ }
+
+ $identities = id(new PhabricatorRepositoryIdentityQuery())
+ ->setViewer($viewer)
+ ->withRelatedPHIDs(array($user->getPHID()))
+ ->execute();
+
+ if (!$identities) {
+ $this->logWarn(
+ pht('NO IDENTITIES'),
+ pht('Found no identities directly related to user.'));
+ continue;
+ }
+
+ $this->rebuildIdentities($identities);
+ }
+ }
+
+ private function rebuildEmails($emails) {
+ $viewer = $this->getViewer();
+
+ foreach ($emails as $email) {
+ $this->logInfo(
+ pht('EMAIL'),
+ pht('Rebuilding identities for email address "%s".', $email));
+
+ $identities = id(new PhabricatorRepositoryIdentityQuery())
+ ->setViewer($viewer)
+ ->withEmailAddresses(array($email))
+ ->execute();
+
+ if (!$identities) {
+ $this->logWarn(
+ pht('NO IDENTITIES'),
+ pht('Found no identities for email address "%s".', $email));
+ continue;
+ }
+
+ $this->rebuildIdentities($identities);
+ }
+ }
+
+ private function rebuildIdentities($identities) {
+ $viewer = $this->getViewer();
+
+ foreach ($identities as $identity) {
+ $raw_identity = $identity->getIdentityName();
+
+ if (isset($this->identityCache[$raw_identity])) {
+ $this->logInfo(
+ pht('SKIP'),
+ pht(
+ 'Identity "%s" has already been rebuilt.',
+ $raw_identity));
+ continue;
+ }
+
+ $this->logInfo(
+ pht('IDENTITY'),
+ pht(
+ 'Rebuilding identity "%s".',
+ $raw_identity));
+
+ $old_auto = $identity->getAutomaticGuessedUserPHID();
+ $old_assign = $identity->getManuallySetUserPHID();
+
+ $identity = id(new DiffusionRepositoryIdentityEngine())
+ ->setViewer($viewer)
+ ->newUpdatedIdentity($identity);
+
+ $this->identityCache[$raw_identity] = $identity;
+
+ $new_auto = $identity->getAutomaticGuessedUserPHID();
+ $new_assign = $identity->getManuallySetUserPHID();
+
+ $same_auto = ($old_auto === $new_auto);
+ $same_assign = ($old_assign === $new_assign);
+
+ if ($same_auto && $same_assign) {
+ $this->logInfo(
+ pht('UNCHANGED'),
+ pht('No changes to identity.'));
+ } else {
+ if (!$same_auto) {
+ $this->logWarn(
+ pht('AUTOMATIC PHID'),
+ pht(
+ 'Automatic user updated from "%s" to "%s".',
+ $this->renderPHID($old_auto),
+ $this->renderPHID($new_auto)));
+ }
+ if (!$same_assign) {
+ $this->logWarn(
+ pht('ASSIGNED PHID'),
+ pht(
+ 'Assigned user updated from "%s" to "%s".',
+ $this->renderPHID($old_assign),
+ $this->renderPHID($new_assign)));
+ }
+ }
+ }
+ }
+
+ private function renderPHID($phid) {
+ if ($phid == null) {
+ return pht('NULL');
+ } else {
+ return $phid;
+ }
+ }
+
}
diff --git a/src/applications/repository/query/PhabricatorRepositoryIdentityQuery.php b/src/applications/repository/query/PhabricatorRepositoryIdentityQuery.php
index 14c2a75f80..7de97de4d6 100644
--- a/src/applications/repository/query/PhabricatorRepositoryIdentityQuery.php
+++ b/src/applications/repository/query/PhabricatorRepositoryIdentityQuery.php
@@ -1,143 +1,160 @@
<?php
final class PhabricatorRepositoryIdentityQuery
extends PhabricatorCursorPagedPolicyAwareQuery {
private $ids;
private $phids;
private $identityNames;
private $emailAddresses;
private $assignedPHIDs;
private $effectivePHIDs;
private $identityNameLike;
private $hasEffectivePHID;
+ private $relatedPHIDs;
public function withIDs(array $ids) {
$this->ids = $ids;
return $this;
}
public function withPHIDs(array $phids) {
$this->phids = $phids;
return $this;
}
public function withIdentityNames(array $names) {
$this->identityNames = $names;
return $this;
}
public function withIdentityNameLike($name_like) {
$this->identityNameLike = $name_like;
return $this;
}
public function withEmailAddresses(array $addresses) {
$this->emailAddresses = $addresses;
return $this;
}
public function withAssignedPHIDs(array $assigned) {
$this->assignedPHIDs = $assigned;
return $this;
}
public function withEffectivePHIDs(array $effective) {
$this->effectivePHIDs = $effective;
return $this;
}
+ public function withRelatedPHIDs(array $related) {
+ $this->relatedPHIDs = $related;
+ return $this;
+ }
+
public function withHasEffectivePHID($has_effective_phid) {
$this->hasEffectivePHID = $has_effective_phid;
return $this;
}
public function newResultObject() {
return new PhabricatorRepositoryIdentity();
}
protected function getPrimaryTableAlias() {
- return 'repository_identity';
+ return 'identity';
}
protected function loadPage() {
return $this->loadStandardPage($this->newResultObject());
}
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
$where = parent::buildWhereClauseParts($conn);
if ($this->ids !== null) {
$where[] = qsprintf(
$conn,
- 'repository_identity.id IN (%Ld)',
+ 'identity.id IN (%Ld)',
$this->ids);
}
if ($this->phids !== null) {
$where[] = qsprintf(
$conn,
- 'repository_identity.phid IN (%Ls)',
+ 'identity.phid IN (%Ls)',
$this->phids);
}
if ($this->assignedPHIDs !== null) {
$where[] = qsprintf(
$conn,
- 'repository_identity.manuallySetUserPHID IN (%Ls)',
+ 'identity.manuallySetUserPHID IN (%Ls)',
$this->assignedPHIDs);
}
if ($this->effectivePHIDs !== null) {
$where[] = qsprintf(
$conn,
- 'repository_identity.currentEffectiveUserPHID IN (%Ls)',
+ 'identity.currentEffectiveUserPHID IN (%Ls)',
$this->effectivePHIDs);
}
if ($this->hasEffectivePHID !== null) {
if ($this->hasEffectivePHID) {
$where[] = qsprintf(
$conn,
- 'repository_identity.currentEffectiveUserPHID IS NOT NULL');
+ 'identity.currentEffectiveUserPHID IS NOT NULL');
} else {
$where[] = qsprintf(
$conn,
- 'repository_identity.currentEffectiveUserPHID IS NULL');
+ 'identity.currentEffectiveUserPHID IS NULL');
}
}
if ($this->identityNames !== null) {
$name_hashes = array();
foreach ($this->identityNames as $name) {
$name_hashes[] = PhabricatorHash::digestForIndex($name);
}
$where[] = qsprintf(
$conn,
- 'repository_identity.identityNameHash IN (%Ls)',
+ 'identity.identityNameHash IN (%Ls)',
$name_hashes);
}
if ($this->emailAddresses !== null) {
$where[] = qsprintf(
$conn,
- 'repository_identity.emailAddress IN (%Ls)',
+ 'identity.emailAddress IN (%Ls)',
$this->emailAddresses);
}
if ($this->identityNameLike != null) {
$where[] = qsprintf(
$conn,
- 'repository_identity.identityNameRaw LIKE %~',
+ 'identity.identityNameRaw LIKE %~',
$this->identityNameLike);
}
+ if ($this->relatedPHIDs !== null) {
+ $where[] = qsprintf(
+ $conn,
+ '(identity.manuallySetUserPHID IN (%Ls) OR
+ identity.currentEffectiveUserPHID IN (%Ls) OR
+ identity.automaticGuessedUserPHID IN (%Ls))',
+ $this->relatedPHIDs,
+ $this->relatedPHIDs,
+ $this->relatedPHIDs);
+ }
+
return $where;
}
public function getQueryApplicationClass() {
return 'PhabricatorDiffusionApplication';
}
}
diff --git a/src/infrastructure/management/PhabricatorManagementWorkflow.php b/src/infrastructure/management/PhabricatorManagementWorkflow.php
index ae33f5d6cc..b1a81201f7 100644
--- a/src/infrastructure/management/PhabricatorManagementWorkflow.php
+++ b/src/infrastructure/management/PhabricatorManagementWorkflow.php
@@ -1,70 +1,191 @@
<?php
abstract class PhabricatorManagementWorkflow extends PhutilArgumentWorkflow {
public function isExecutable() {
return true;
}
public function getViewer() {
// Some day, we might provide a more general viewer mechanism to scripts.
// For now, workflows can call this method for convenience and future
// flexibility.
return PhabricatorUser::getOmnipotentUser();
}
protected function parseTimeArgument($time) {
if (!strlen($time)) {
return null;
}
$epoch = strtotime($time);
if ($epoch <= 0) {
throw new PhutilArgumentUsageException(
pht('Unable to parse time "%s".', $time));
}
return $epoch;
}
protected function newContentSource() {
return PhabricatorContentSource::newForSource(
PhabricatorConsoleContentSource::SOURCECONST);
}
protected function logInfo($label, $message) {
$this->logRaw(
tsprintf(
"**<bg:blue> %s </bg>** %s\n",
$label,
$message));
}
protected function logOkay($label, $message) {
$this->logRaw(
tsprintf(
"**<bg:green> %s </bg>** %s\n",
$label,
$message));
}
protected function logWarn($label, $message) {
$this->logRaw(
tsprintf(
"**<bg:yellow> %s </bg>** %s\n",
$label,
$message));
}
protected function logFail($label, $message) {
$this->logRaw(
tsprintf(
"**<bg:red> %s </bg>** %s\n",
$label,
$message));
}
private function logRaw($message) {
fprintf(STDERR, '%s', $message);
}
+ final protected function loadUsersFromArguments(array $identifiers) {
+ if (!$identifiers) {
+ return array();
+ }
+
+ $ids = array();
+ $phids = array();
+ $usernames = array();
+
+ $user_type = PhabricatorPeopleUserPHIDType::TYPECONST;
+
+ foreach ($identifiers as $identifier) {
+ // If the value is a user PHID, treat as a PHID.
+ if (phid_get_type($identifier) === $user_type) {
+ $phids[$identifier] = $identifier;
+ continue;
+ }
+
+ // If the value is "@..." and then some text, treat it as a username.
+ if ((strlen($identifier) > 1) && ($identifier[0] == '@')) {
+ $usernames[$identifier] = substr($identifier, 1);
+ continue;
+ }
+
+ // If the value is digits, treat it as both an ID and a username.
+ // Entirely numeric usernames, like "1234", are valid.
+ if (ctype_digit($identifier)) {
+ $ids[$identifier] = $identifier;
+ $usernames[$identifier] = $identifier;
+ continue;
+ }
+
+ // Otherwise, treat it as an unescaped username.
+ $usernames[$identifier] = $identifier;
+ }
+
+ $viewer = $this->getViewer();
+ $results = array();
+
+ if ($phids) {
+ $users = id(new PhabricatorPeopleQuery())
+ ->setViewer($viewer)
+ ->withPHIDs($phids)
+ ->execute();
+ foreach ($users as $user) {
+ $phid = $user->getPHID();
+ $results[$phid][] = $user;
+ }
+ }
+
+ if ($usernames) {
+ $users = id(new PhabricatorPeopleQuery())
+ ->setViewer($viewer)
+ ->withUsernames($usernames)
+ ->execute();
+
+ $reverse_map = array();
+ foreach ($usernames as $identifier => $username) {
+ $username = phutil_utf8_strtolower($username);
+ $reverse_map[$username][] = $identifier;
+ }
+
+ foreach ($users as $user) {
+ $username = $user->getUsername();
+ $username = phutil_utf8_strtolower($username);
+
+ $reverse_identifiers = idx($reverse_map, $username, array());
+
+ if (count($reverse_identifiers) > 1) {
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'Multiple user identifiers (%s) correspond to the same user. '.
+ 'Identify each user exactly once.',
+ implode(', ', $reverse_identifiers)));
+ }
+
+ foreach ($reverse_identifiers as $reverse_identifier) {
+ $results[$reverse_identifier][] = $user;
+ }
+ }
+ }
+
+ if ($ids) {
+ $users = id(new PhabricatorPeopleQuery())
+ ->setViewer($viewer)
+ ->withIDs($ids)
+ ->execute();
+
+ foreach ($users as $user) {
+ $id = $user->getID();
+ $results[$id][] = $user;
+ }
+ }
+
+ $list = array();
+ foreach ($identifiers as $identifier) {
+ $users = idx($results, $identifier, array());
+ if (!$users) {
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'No user "%s" exists. Specify users by username, ID, or PHID.',
+ $identifier));
+ }
+
+ if (count($users) > 1) {
+ // This can happen if you have a user "@25", a user with ID 25, and
+ // specify "--user 25". You can disambiguate this by specifying
+ // "--user @25".
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'Identifier "%s" matches multiple users. Specify each user '.
+ 'unambiguously with "@username" or by using user PHIDs.',
+ $identifier));
+ }
+
+ $list[] = head($users);
+ }
+
+ return $list;
+ }
+
}

File Metadata

Mime Type
text/x-diff
Expires
Sun, Jul 27, 11:31 AM (6 d, 4 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
184518
Default Alt Text
(30 KB)

Event Timeline