Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15373319
D21336.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
27 KB
Referenced Files
None
Subscribers
None
D21336.diff
View Options
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -225,6 +225,7 @@
'ArcanistGitRawCommitTestCase' => 'repository/raw/__tests__/ArcanistGitRawCommitTestCase.php',
'ArcanistGitRepositoryMarkerQuery' => 'repository/marker/ArcanistGitRepositoryMarkerQuery.php',
'ArcanistGitUpstreamPath' => 'repository/api/ArcanistGitUpstreamPath.php',
+ 'ArcanistGitWorkEngine' => 'work/ArcanistGitWorkEngine.php',
'ArcanistGitWorkingCopy' => 'workingcopy/ArcanistGitWorkingCopy.php',
'ArcanistGitWorkingCopyRevisionHardpointQuery' => 'query/ArcanistGitWorkingCopyRevisionHardpointQuery.php',
'ArcanistGlobalVariableXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistGlobalVariableXHPASTLinterRule.php',
@@ -336,6 +337,7 @@
'ArcanistMercurialParser' => 'repository/parser/ArcanistMercurialParser.php',
'ArcanistMercurialParserTestCase' => 'repository/parser/__tests__/ArcanistMercurialParserTestCase.php',
'ArcanistMercurialRepositoryMarkerQuery' => 'repository/marker/ArcanistMercurialRepositoryMarkerQuery.php',
+ 'ArcanistMercurialWorkEngine' => 'work/ArcanistMercurialWorkEngine.php',
'ArcanistMercurialWorkingCopy' => 'workingcopy/ArcanistMercurialWorkingCopy.php',
'ArcanistMercurialWorkingCopyRevisionHardpointQuery' => 'query/ArcanistMercurialWorkingCopyRevisionHardpointQuery.php',
'ArcanistMergeConflictLinter' => 'lint/linter/ArcanistMergeConflictLinter.php',
@@ -538,8 +540,11 @@
'ArcanistWeldWorkflow' => 'workflow/ArcanistWeldWorkflow.php',
'ArcanistWhichWorkflow' => 'workflow/ArcanistWhichWorkflow.php',
'ArcanistWildConfigOption' => 'config/option/ArcanistWildConfigOption.php',
+ 'ArcanistWorkEngine' => 'work/ArcanistWorkEngine.php',
+ 'ArcanistWorkWorkflow' => 'workflow/ArcanistWorkWorkflow.php',
'ArcanistWorkflow' => 'workflow/ArcanistWorkflow.php',
'ArcanistWorkflowArgument' => 'toolset/ArcanistWorkflowArgument.php',
+ 'ArcanistWorkflowEngine' => 'engine/ArcanistWorkflowEngine.php',
'ArcanistWorkflowGitHardpointQuery' => 'query/ArcanistWorkflowGitHardpointQuery.php',
'ArcanistWorkflowInformation' => 'toolset/ArcanistWorkflowInformation.php',
'ArcanistWorkflowMercurialHardpointQuery' => 'query/ArcanistWorkflowMercurialHardpointQuery.php',
@@ -1253,6 +1258,7 @@
'ArcanistGitRawCommitTestCase' => 'PhutilTestCase',
'ArcanistGitRepositoryMarkerQuery' => 'ArcanistRepositoryMarkerQuery',
'ArcanistGitUpstreamPath' => 'Phobject',
+ 'ArcanistGitWorkEngine' => 'ArcanistWorkEngine',
'ArcanistGitWorkingCopy' => 'ArcanistWorkingCopy',
'ArcanistGitWorkingCopyRevisionHardpointQuery' => 'ArcanistWorkflowGitHardpointQuery',
'ArcanistGlobalVariableXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
@@ -1322,7 +1328,7 @@
'ArcanistLambdaFuncFunctionXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistLandCommit' => 'Phobject',
'ArcanistLandCommitSet' => 'Phobject',
- 'ArcanistLandEngine' => 'Phobject',
+ 'ArcanistLandEngine' => 'ArcanistWorkflowEngine',
'ArcanistLandSymbol' => 'Phobject',
'ArcanistLandTarget' => 'Phobject',
'ArcanistLandWorkflow' => 'ArcanistArcWorkflow',
@@ -1355,7 +1361,10 @@
'ArcanistLogicalOperatorsXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistLowercaseFunctionsXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistLowercaseFunctionsXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
- 'ArcanistMarkerRef' => 'ArcanistRef',
+ 'ArcanistMarkerRef' => array(
+ 'ArcanistRef',
+ 'ArcanistDisplayRefInterface',
+ ),
'ArcanistMarkersWorkflow' => 'ArcanistArcWorkflow',
'ArcanistMercurialAPI' => 'ArcanistRepositoryAPI',
'ArcanistMercurialCommitMessageHardpointQuery' => 'ArcanistWorkflowMercurialHardpointQuery',
@@ -1364,6 +1373,7 @@
'ArcanistMercurialParser' => 'Phobject',
'ArcanistMercurialParserTestCase' => 'PhutilTestCase',
'ArcanistMercurialRepositoryMarkerQuery' => 'ArcanistRepositoryMarkerQuery',
+ 'ArcanistMercurialWorkEngine' => 'ArcanistWorkEngine',
'ArcanistMercurialWorkingCopy' => 'ArcanistWorkingCopy',
'ArcanistMercurialWorkingCopyRevisionHardpointQuery' => 'ArcanistWorkflowMercurialHardpointQuery',
'ArcanistMergeConflictLinter' => 'ArcanistLinter',
@@ -1576,8 +1586,11 @@
'ArcanistWeldWorkflow' => 'ArcanistArcWorkflow',
'ArcanistWhichWorkflow' => 'ArcanistWorkflow',
'ArcanistWildConfigOption' => 'ArcanistConfigOption',
+ 'ArcanistWorkEngine' => 'ArcanistWorkflowEngine',
+ 'ArcanistWorkWorkflow' => 'ArcanistArcWorkflow',
'ArcanistWorkflow' => 'Phobject',
'ArcanistWorkflowArgument' => 'Phobject',
+ 'ArcanistWorkflowEngine' => 'Phobject',
'ArcanistWorkflowGitHardpointQuery' => 'ArcanistRuntimeHardpointQuery',
'ArcanistWorkflowInformation' => 'Phobject',
'ArcanistWorkflowMercurialHardpointQuery' => 'ArcanistRuntimeHardpointQuery',
diff --git a/src/engine/ArcanistWorkflowEngine.php b/src/engine/ArcanistWorkflowEngine.php
new file mode 100644
--- /dev/null
+++ b/src/engine/ArcanistWorkflowEngine.php
@@ -0,0 +1,48 @@
+<?php
+
+abstract class ArcanistWorkflowEngine
+ extends Phobject {
+
+ private $workflow;
+ private $viewer;
+ private $logEngine;
+ private $repositoryAPI;
+
+ final public function setViewer($viewer) {
+ $this->viewer = $viewer;
+ return $this;
+ }
+
+ final public function getViewer() {
+ return $this->viewer;
+ }
+
+ final public function setWorkflow(ArcanistWorkflow $workflow) {
+ $this->workflow = $workflow;
+ return $this;
+ }
+
+ final public function getWorkflow() {
+ return $this->workflow;
+ }
+
+ final public function setRepositoryAPI(
+ ArcanistRepositoryAPI $repository_api) {
+ $this->repositoryAPI = $repository_api;
+ return $this;
+ }
+
+ final public function getRepositoryAPI() {
+ return $this->repositoryAPI;
+ }
+
+ final public function setLogEngine(ArcanistLogEngine $log_engine) {
+ $this->logEngine = $log_engine;
+ return $this;
+ }
+
+ final public function getLogEngine() {
+ return $this->logEngine;
+ }
+
+}
diff --git a/src/hardpoint/ArcanistHardpointObject.php b/src/hardpoint/ArcanistHardpointObject.php
--- a/src/hardpoint/ArcanistHardpointObject.php
+++ b/src/hardpoint/ArcanistHardpointObject.php
@@ -5,6 +5,12 @@
private $hardpointList;
+ public function __clone() {
+ if ($this->hardpointList) {
+ $this->hardpointList = clone $this->hardpointList;
+ }
+ }
+
final public function getHardpoint($hardpoint) {
return $this->getHardpointList()->getHardpoint(
$this,
diff --git a/src/land/engine/ArcanistLandEngine.php b/src/land/engine/ArcanistLandEngine.php
--- a/src/land/engine/ArcanistLandEngine.php
+++ b/src/land/engine/ArcanistLandEngine.php
@@ -1,11 +1,7 @@
<?php
-abstract class ArcanistLandEngine extends Phobject {
-
- private $workflow;
- private $viewer;
- private $logEngine;
- private $repositoryAPI;
+abstract class ArcanistLandEngine
+ extends ArcanistWorkflowEngine {
private $sourceRefs;
private $shouldHold;
@@ -33,15 +29,6 @@
private $localState;
- final public function setViewer($viewer) {
- $this->viewer = $viewer;
- return $this;
- }
-
- final public function getViewer() {
- return $this->viewer;
- }
-
final public function setOntoRemote($onto_remote) {
$this->ontoRemote = $onto_remote;
return $this;
@@ -96,34 +83,6 @@
return $this->intoLocal;
}
- final public function setWorkflow($workflow) {
- $this->workflow = $workflow;
- return $this;
- }
-
- final public function getWorkflow() {
- return $this->workflow;
- }
-
- final public function setRepositoryAPI(
- ArcanistRepositoryAPI $repository_api) {
- $this->repositoryAPI = $repository_api;
- return $this;
- }
-
- final public function getRepositoryAPI() {
- return $this->repositoryAPI;
- }
-
- final public function setLogEngine(ArcanistLogEngine $log_engine) {
- $this->logEngine = $log_engine;
- return $this;
- }
-
- final public function getLogEngine() {
- return $this->logEngine;
- }
-
final public function setShouldHold($should_hold) {
$this->shouldHold = $should_hold;
return $this;
diff --git a/src/repository/api/ArcanistGitAPI.php b/src/repository/api/ArcanistGitAPI.php
--- a/src/repository/api/ArcanistGitAPI.php
+++ b/src/repository/api/ArcanistGitAPI.php
@@ -1746,6 +1746,10 @@
return new ArcanistGitLandEngine();
}
+ protected function newWorkEngine() {
+ return new ArcanistGitWorkEngine();
+ }
+
public function newLocalState() {
return id(new ArcanistGitLocalState())
->setRepositoryAPI($this);
diff --git a/src/repository/api/ArcanistMercurialAPI.php b/src/repository/api/ArcanistMercurialAPI.php
--- a/src/repository/api/ArcanistMercurialAPI.php
+++ b/src/repository/api/ArcanistMercurialAPI.php
@@ -1134,6 +1134,10 @@
return new ArcanistMercurialLandEngine();
}
+ protected function newWorkEngine() {
+ return new ArcanistMercurialWorkEngine();
+ }
+
public function newLocalState() {
return id(new ArcanistMercurialLocalState())
->setRepositoryAPI($this);
diff --git a/src/repository/api/ArcanistRepositoryAPI.php b/src/repository/api/ArcanistRepositoryAPI.php
--- a/src/repository/api/ArcanistRepositoryAPI.php
+++ b/src/repository/api/ArcanistRepositoryAPI.php
@@ -763,6 +763,20 @@
return null;
}
+ final public function getWorkEngine() {
+ $engine = $this->newWorkEngine();
+
+ if ($engine) {
+ $engine->setRepositoryAPI($this);
+ }
+
+ return $engine;
+ }
+
+ protected function newWorkEngine() {
+ return null;
+ }
+
final public function getSupportedMarkerTypes() {
return $this->newSupportedMarkerTypes();
}
@@ -780,4 +794,8 @@
throw new PhutilMethodNotImplementedException();
}
+ final public function getDisplayHash($hash) {
+ return substr($hash, 0, 12);
+ }
+
}
diff --git a/src/repository/marker/ArcanistMarkerRef.php b/src/repository/marker/ArcanistMarkerRef.php
--- a/src/repository/marker/ArcanistMarkerRef.php
+++ b/src/repository/marker/ArcanistMarkerRef.php
@@ -1,9 +1,12 @@
<?php
final class ArcanistMarkerRef
- extends ArcanistRef {
+ extends ArcanistRef
+ implements
+ ArcanistDisplayRefInterface {
- const HARDPOINT_COMMITREF = 'commitRef';
+ const HARDPOINT_COMMITREF = 'arc.marker.commitRef';
+ const HARDPOINT_WORKINGCOPYSTATEREF = 'arc.marker.workingCopyStateRef';
const TYPE_BRANCH = 'branch';
const TYPE_BOOKMARK = 'bookmark';
@@ -13,18 +16,38 @@
private $epoch;
private $markerHash;
private $commitHash;
+ private $displayHash;
private $treeHash;
private $summary;
private $message;
private $isActive = false;
public function getRefDisplayName() {
- return pht('Marker %s', $this->getName());
+ return $this->getDisplayRefObjectName();
+ }
+
+ public function getDisplayRefObjectName() {
+ switch ($this->getMarkerType()) {
+ case self::TYPE_BRANCH:
+ return pht('Branch "%s"', $this->getName());
+ case self::TYPE_BOOKMARK:
+ return pht('Bookmark "%s"', $this->getName());
+ default:
+ return pht('Marker "%s"', $this->getName());
+ }
+ }
+
+ public function getDisplayRefTitle() {
+ return pht(
+ '%s %s',
+ $this->getDisplayHash(),
+ $this->getSummary());
}
protected function newHardpoints() {
return array(
$this->newHardpoint(self::HARDPOINT_COMMITREF),
+ $this->newHardpoint(self::HARDPOINT_WORKINGCOPYSTATEREF),
);
}
@@ -64,6 +87,17 @@
return $this->markerHash;
}
+ public function setDisplayHash($display_hash) {
+ $this->displayHash = $display_hash;
+ return $this;
+ }
+
+ public function getDisplayHash() {
+ return $this->displayHash;
+ }
+
+
+
public function setCommitHash($commit_hash) {
$this->commitHash = $commit_hash;
return $this;
@@ -125,4 +159,12 @@
return $this->getHardpoint(self::HARDPOINT_COMMITREF);
}
+ public function attachWorkingCopyStateRef(ArcanistWorkingCopyStateRef $ref) {
+ return $this->attachHardpoint(self::HARDPOINT_WORKINGCOPYSTATEREF, $ref);
+ }
+
+ public function getWorkingCopyStateRef() {
+ return $this->getHardpoint(self::HARDPOINT_WORKINGCOPYSTATEREF);
+ }
+
}
diff --git a/src/repository/marker/ArcanistMercurialRepositoryMarkerQuery.php b/src/repository/marker/ArcanistMercurialRepositoryMarkerQuery.php
--- a/src/repository/marker/ArcanistMercurialRepositoryMarkerQuery.php
+++ b/src/repository/marker/ArcanistMercurialRepositoryMarkerQuery.php
@@ -100,6 +100,7 @@
}
$message = $fields[4];
+ $message_lines = phutil_split_lines($message, false);
$commit_ref = $api->newCommitRef()
->setCommitHash($node)
@@ -107,6 +108,7 @@
$template = id(new ArcanistMarkerRef())
->setCommitHash($node)
+ ->setSummary(head($message_lines))
->attachCommitRef($commit_ref);
if ($is_bookmarks) {
diff --git a/src/repository/marker/ArcanistRepositoryMarkerQuery.php b/src/repository/marker/ArcanistRepositoryMarkerQuery.php
--- a/src/repository/marker/ArcanistRepositoryMarkerQuery.php
+++ b/src/repository/marker/ArcanistRepositoryMarkerQuery.php
@@ -6,6 +6,7 @@
private $repositoryAPI;
private $isActive;
private $markerTypes;
+ private $names;
private $commitHashes;
private $ancestorCommitHashes;
@@ -23,14 +24,47 @@
return $this;
}
+ final public function withNames(array $names) {
+ $this->names = array_fuse($names);
+ return $this;
+ }
+
final public function withIsActive($active) {
$this->isActive = $active;
return $this;
}
+ final public function executeOne() {
+ $markers = $this->execute();
+
+ if (!$markers) {
+ return null;
+ }
+
+ if (count($markers) > 1) {
+ throw new Exception(
+ pht(
+ 'Query matched multiple markers, expected zero or one.'));
+ }
+
+ return head($markers);
+ }
+
final public function execute() {
$markers = $this->newRefMarkers();
+ $api = $this->getRepositoryAPI();
+ foreach ($markers as $marker) {
+ $state_ref = id(new ArcanistWorkingCopyStateRef())
+ ->setCommitRef($marker->getCommitRef());
+
+ $marker->attachWorkingCopyStateRef($state_ref);
+
+ $hash = $marker->getCommitHash();
+ $hash = $api->getDisplayHash($hash);
+ $marker->setDisplayHash($hash);
+ }
+
$types = $this->markerTypes;
if ($types !== null) {
foreach ($markers as $key => $marker) {
@@ -40,6 +74,15 @@
}
}
+ $names = $this->names;
+ if ($names !== null) {
+ foreach ($markers as $key => $marker) {
+ if (!isset($names[$marker->getName()])) {
+ unset($markers[$key]);
+ }
+ }
+ }
+
if ($this->isActive !== null) {
foreach ($markers as $key => $marker) {
if ($marker->getIsActive() !== $this->isActive) {
@@ -48,6 +91,7 @@
}
}
+
return $this->sortMarkers($markers);
}
diff --git a/src/repository/state/ArcanistGitLocalState.php b/src/repository/state/ArcanistGitLocalState.php
--- a/src/repository/state/ArcanistGitLocalState.php
+++ b/src/repository/state/ArcanistGitLocalState.php
@@ -42,7 +42,7 @@
}
$log = $this->getWorkflow()->getLogEngine();
- $log->writeStatus(pht('SAVE STATE'), $where);
+ $log->writeTrace(pht('SAVE STATE'), $where);
}
protected function executeRestoreLocalState() {
diff --git a/src/work/ArcanistGitWorkEngine.php b/src/work/ArcanistGitWorkEngine.php
new file mode 100644
--- /dev/null
+++ b/src/work/ArcanistGitWorkEngine.php
@@ -0,0 +1,57 @@
+<?php
+
+final class ArcanistGitWorkEngine
+ extends ArcanistWorkEngine {
+
+ protected function getDefaultStartSymbol() {
+ $api = $this->getRepositoryAPI();
+
+ // NOTE: In Git, we're trying to find the current branch name because the
+ // behavior of "--track" depends on the symbol we pass.
+
+ $marker = $api->newMarkerRefQuery()
+ ->withIsActive(true)
+ ->withMarkerTypes(array(ArcanistMarkerRef::TYPE_BRANCH))
+ ->executeOne();
+ if ($marker) {
+ return $marker->getName();
+ }
+
+ return $api->getWorkingCopyRevision();
+ }
+
+ protected function newMarker($symbol, $start) {
+ $api = $this->getRepositoryAPI();
+ $log = $this->getLogEngine();
+
+ $log->writeStatus(
+ pht('NEW BRANCH'),
+ pht(
+ 'Creating new branch "%s" from "%s".',
+ $symbol,
+ $start));
+
+ $future = $api->newFuture(
+ 'checkout --track -b %s %s --',
+ $symbol,
+ $start);
+ $future->resolve();
+ }
+
+ protected function moveToMarker(ArcanistMarkerRef $marker) {
+ $api = $this->getRepositoryAPI();
+ $log = $this->getLogEngine();
+
+ $log->writeStatus(
+ pht('BRANCH'),
+ pht(
+ 'Checking out branch "%s".',
+ $marker->getName()));
+
+ $future = $api->newFuture(
+ 'checkout %s --',
+ $marker->getName());
+ $future->resolve();
+ }
+
+}
diff --git a/src/work/ArcanistMercurialWorkEngine.php b/src/work/ArcanistMercurialWorkEngine.php
new file mode 100644
--- /dev/null
+++ b/src/work/ArcanistMercurialWorkEngine.php
@@ -0,0 +1,56 @@
+<?php
+
+final class ArcanistMercurialWorkEngine
+ extends ArcanistWorkEngine {
+
+ protected function getDefaultStartSymbol() {
+ $api = $this->getRepositoryAPI();
+ return $api->getWorkingCopyRevision();
+ }
+
+ protected function newMarker($symbol, $start) {
+ $api = $this->getRepositoryAPI();
+ $log = $this->getLogEngine();
+
+ $log->writeStatus(
+ pht('NEW BOOKMARK'),
+ pht(
+ 'Creating new bookmark "%s" from "%s".',
+ $symbol,
+ $start));
+
+ if ($start !== $this->getDefaultStartSymbol()) {
+ $future = $api->newFuture('update -- %s', $start);
+ $future->resolve();
+ }
+
+ $future = $api->newFuture('bookmark %s --', $symbol);
+ $future->resolve();
+ }
+
+ protected function moveToMarker(ArcanistMarkerRef $marker) {
+ $api = $this->getRepositoryAPI();
+ $log = $this->getLogEngine();
+
+ if ($marker->isBookmark()) {
+ $log->writeStatus(
+ pht('BOOKMARK'),
+ pht(
+ 'Checking out bookmark "%s".',
+ $marker->getName()));
+ } else {
+ $log->writeStatus(
+ pht('BRANCH'),
+ pht(
+ 'Checking out branch "%s".',
+ $marker->getName()));
+ }
+
+ $future = $api->newFuture(
+ 'checkout %s --',
+ $marker->getName());
+
+ $future->resolve();
+ }
+
+}
diff --git a/src/work/ArcanistWorkEngine.php b/src/work/ArcanistWorkEngine.php
new file mode 100644
--- /dev/null
+++ b/src/work/ArcanistWorkEngine.php
@@ -0,0 +1,215 @@
+<?php
+
+abstract class ArcanistWorkEngine
+ extends ArcanistWorkflowEngine {
+
+ private $symbolArgument;
+ private $startArgument;
+
+ final public function setSymbolArgument($symbol_argument) {
+ $this->symbolArgument = $symbol_argument;
+ return $this;
+ }
+
+ final public function getSymbolArgument() {
+ return $this->symbolArgument;
+ }
+
+ final public function setStartArgument($start_argument) {
+ $this->startArgument = $start_argument;
+ return $this;
+ }
+
+ final public function getStartArgument() {
+ return $this->startArgument;
+ }
+
+ final public function execute() {
+ $workflow = $this->getWorkflow();
+ $api = $this->getRepositoryAPI();
+
+ $local_state = $api->newLocalState()
+ ->setWorkflow($workflow)
+ ->saveLocalState();
+
+ $symbol = $this->getSymbolArgument();
+
+ $markers = $api->newMarkerRefQuery()
+ ->withNames(array($symbol))
+ ->execute();
+
+ if ($markers) {
+ if (count($markers) > 1) {
+
+ // TODO: This almost certainly means the symbol is a Mercurial branch
+ // with multiple heads. We can pick some head.
+
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'Symbol "%s" is ambiguous.',
+ $symbol));
+ }
+
+ $target = head($markers);
+ $this->moveToMarker($target);
+ $local_state->discardLocalState();
+ return;
+ }
+
+ $revision_marker = $this->workOnRevision($symbol);
+ if ($revision_marker) {
+ $this->moveToMarker($revision_marker);
+ $local_state->discardLocalState();
+ return;
+ }
+
+ $task_marker = $this->workOnTask($symbol);
+ if ($task_marker) {
+ $this->moveToMarker($task_marker);
+ $local_state->discardLocalState();
+ return;
+ }
+
+ // NOTE: We're resolving this symbol so we can raise an error message if
+ // it's bogus, but we're using the symbol (not the resolved version) to
+ // actually create the new marker. This matters in Git because it impacts
+ // the behavior of "--track" when we pass a branch name.
+
+ $start = $this->getStartArgument();
+ if ($start !== null) {
+ $start_commit = $api->getCanonicalRevisionName($start);
+ if (!$start_commit) {
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'Unable to resolve startpoint "%s".',
+ $start));
+ }
+ } else {
+ $start = $this->getDefaultStartSymbol();
+ }
+
+ $this->newMarker($symbol, $start);
+ $local_state->discardLocalState();
+ }
+
+ abstract protected function newMarker($symbol, $start);
+ abstract protected function moveToMarker(ArcanistMarkerRef $marker);
+ abstract protected function getDefaultStartSymbol();
+
+ private function workOnRevision($symbol) {
+ $workflow = $this->getWorkflow();
+ $api = $this->getRepositoryAPI();
+ $log = $this->getLogEngine();
+
+ try {
+ $revision_symbol = id(new ArcanistRevisionSymbolRef())
+ ->setSymbol($symbol);
+ } catch (Exception $ex) {
+ return;
+ }
+
+ $workflow->loadHardpoints(
+ $revision_symbol,
+ ArcanistSymbolRef::HARDPOINT_OBJECT);
+
+ $revision_ref = $revision_symbol->getObject();
+ if (!$revision_ref) {
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'No revision "%s" exists, or you do not have permission to '.
+ 'view it.',
+ $symbol));
+ }
+
+ $markers = $api->newMarkerRefQuery()
+ ->execute();
+
+ $state_refs = mpull($markers, 'getWorkingCopyStateRef');
+
+ $workflow->loadHardpoints(
+ $state_refs,
+ ArcanistWorkingCopyStateRef::HARDPOINT_REVISIONREFS);
+
+ $selected = array();
+ foreach ($markers as $marker) {
+ $state_ref = $marker->getWorkingCopyStateRef();
+ $revision_refs = $state_ref->getRevisionRefs();
+ $revision_refs = mpull($revision_refs, null, 'getPHID');
+
+ if (isset($revision_refs[$revision_ref->getPHID()])) {
+ $selected[] = $marker;
+ }
+ }
+
+ if (!$selected) {
+
+ // TODO: We could patch/load here.
+
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'Revision "%s" was not found anywhere in this working copy.',
+ $revision_ref->getMonogram()));
+ }
+
+ if (count($selected) > 1) {
+ $selected = msort($selected, 'getEpoch');
+
+ echo tsprintf(
+ "\n%!\n%W\n\n",
+ pht('AMBIGUOUS MARKER'),
+ pht(
+ 'More than one marker in the local working copy is associated '.
+ 'with the revision "%s", using the most recent one.',
+ $revision_ref->getMonogram()));
+
+ foreach ($selected as $marker) {
+ echo tsprintf('%s', $marker->newDisplayRef());
+ }
+
+ echo tsprintf("\n");
+
+ $target = last($selected);
+ } else {
+ $target = head($selected);
+ }
+
+ $log->writeStatus(
+ pht('REVISION'),
+ pht('Resuming work on revision:'));
+
+ echo tsprintf('%s', $revision_ref->newDisplayRef());
+ echo tsprintf("\n");
+
+ return $target;
+ }
+
+ private function workOnTask($symbol) {
+ $workflow = $this->getWorkflow();
+
+ try {
+ $task_symbol = id(new ArcanistTaskSymbolRef())
+ ->setSymbol($symbol);
+ } catch (Exception $ex) {
+ return;
+ }
+
+ $workflow->loadHardpoints(
+ $task_symbol,
+ ArcanistSymbolRef::HARDPOINT_OBJECT);
+
+ $task_ref = $task_symbol->getObject();
+ if (!$task_ref) {
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'No task "%s" exists, or you do not have permission to view it.',
+ $symbol));
+ }
+
+ throw new Exception(pht('TODO: Implement this workflow.'));
+
+ $this->loadHardpoints(
+ $task_ref,
+ ArcanistTaskRef::HARDPOINT_REVISIONREFS);
+ }
+
+}
diff --git a/src/workflow/ArcanistWorkWorkflow.php b/src/workflow/ArcanistWorkWorkflow.php
new file mode 100644
--- /dev/null
+++ b/src/workflow/ArcanistWorkWorkflow.php
@@ -0,0 +1,95 @@
+<?php
+
+final class ArcanistWorkWorkflow
+ extends ArcanistArcWorkflow {
+
+ public function getWorkflowName() {
+ return 'work';
+ }
+
+ public function getWorkflowArguments() {
+ return array(
+ $this->newWorkflowArgument('start')
+ ->setParameter('symbol')
+ ->setHelp(
+ pht(
+ 'When creating a new branch or bookmark, use this as the '.
+ 'branch point.')),
+ $this->newWorkflowArgument('symbol')
+ ->setWildcard(true),
+ );
+ }
+
+ public function getWorkflowInformation() {
+ $help = pht(<<<EOHELP
+Begin or resume work on a branch, bookmark, task, or revision.
+
+The __symbol__ may be a branch or bookmark name, a revision name (like "D123"),
+a task name (like "T123"), or a new symbol.
+
+If you provide a symbol which currently does not identify any ongoing work,
+Arcanist will create a new branch or bookmark with the name you provide.
+
+If you provide the name of an existing branch or bookmark, Arcanist will switch
+to that branch or bookmark.
+
+If you provide the name of a revision or task, Arcanist will look for a related
+branch or bookmark that exists in the working copy. If it finds one, it will
+switch to it. If it does not find one, it will attempt to create a new branch
+or bookmark.
+
+When "arc work" creates a branch or bookmark, it will use "--start" as the
+branchpoint if it is provided. Otherwise, the current working copy state will
+serve as the starting point.
+EOHELP
+ );
+
+ return $this->newWorkflowInformation()
+ ->setSynopsis(pht('Begin or resume work.'))
+ ->addExample(pht('**work** [--start __start__] __symbol__'))
+ ->setHelp($help);
+ }
+
+ public function runWorkflow() {
+ $api = $this->getRepositoryAPI();
+
+ $work_engine = $api->getWorkEngine();
+ if (!$work_engine) {
+ throw new PhutilArgumentUsageException(
+ pht(
+ '"arc work" must be run in a Git or Mercurial working copy.'));
+ }
+
+ $argv = $this->getArgument('symbol');
+ if (count($argv) === 0) {
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'Provide a branch, bookmark, task, or revision name to begin '.
+ 'or resume work on.'));
+ } else if (count($argv) === 1) {
+ $symbol_argument = $argv[0];
+ if (!strlen($symbol_argument)) {
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'Provide a nonempty symbol to begin or resume work on.'));
+ }
+ } else {
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'Too many arguments: provide exactly one argument.'));
+ }
+
+ $start_argument = $this->getArgument('start');
+
+ $work_engine
+ ->setViewer($this->getViewer())
+ ->setWorkflow($this)
+ ->setLogEngine($this->getLogEngine())
+ ->setSymbolArgument($symbol_argument)
+ ->setStartArgument($start_argument)
+ ->execute();
+
+ return 0;
+ }
+
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Mar 13, 3:29 PM (1 w, 5 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7624681
Default Alt Text
D21336.diff (27 KB)
Attached To
Mode
D21336: Implement "arc work", to replace "arc feature"
Attached
Detach File
Event Timeline
Log In to Comment