mirror of
https://we.phorge.it/source/arcanist.git
synced 2024-11-28 09:42:40 +01:00
Merge the remainder of the "experimental" branch
Summary: Depends on D20986. Ref T13395. This //mostly// collapses the entire "experimental" branch into "master". I plan to change the "Ref/Hardpoint" pattern to become future oriented, but this is more steps forward than sideways. Test Plan: Ran various `arc` workflows. Maniphest Tasks: T13395 Differential Revision: https://secure.phabricator.com/D20987
This commit is contained in:
parent
4c36860c43
commit
8c4f6ce161
40 changed files with 2756 additions and 418 deletions
|
@ -35,6 +35,10 @@ $base_args->parsePartial(
|
||||||
'param' => 'token',
|
'param' => 'token',
|
||||||
'help' => pht('Use a specific authentication token.'),
|
'help' => pht('Use a specific authentication token.'),
|
||||||
),
|
),
|
||||||
|
array(
|
||||||
|
'name' => 'anonymous',
|
||||||
|
'help' => pht('Run workflow as a public user, without authenticating.'),
|
||||||
|
),
|
||||||
array(
|
array(
|
||||||
'name' => 'conduit-version',
|
'name' => 'conduit-version',
|
||||||
'param' => 'version',
|
'param' => 'version',
|
||||||
|
@ -64,6 +68,7 @@ $force_conduit_version = $base_args->getArg('conduit-version');
|
||||||
$conduit_timeout = $base_args->getArg('conduit-timeout');
|
$conduit_timeout = $base_args->getArg('conduit-timeout');
|
||||||
$skip_arcconfig = $base_args->getArg('skip-arcconfig');
|
$skip_arcconfig = $base_args->getArg('skip-arcconfig');
|
||||||
$custom_arcrc = $base_args->getArg('arcrc-file');
|
$custom_arcrc = $base_args->getArg('arcrc-file');
|
||||||
|
$is_anonymous = $base_args->getArg('anonymous');
|
||||||
$load = $base_args->getArg('load-phutil-library');
|
$load = $base_args->getArg('load-phutil-library');
|
||||||
$help = $base_args->getArg('help');
|
$help = $base_args->getArg('help');
|
||||||
$args = array_values($base_args->getUnconsumedArgumentVector());
|
$args = array_values($base_args->getUnconsumedArgumentVector());
|
||||||
|
@ -323,6 +328,10 @@ try {
|
||||||
$conduit_token = $force_token;
|
$conduit_token = $force_token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($is_anonymous) {
|
||||||
|
$conduit_token = null;
|
||||||
|
}
|
||||||
|
|
||||||
$description = implode(' ', $original_argv);
|
$description = implode(' ', $original_argv);
|
||||||
$credentials = array(
|
$credentials = array(
|
||||||
'user' => $user_name,
|
'user' => $user_name,
|
||||||
|
@ -332,6 +341,23 @@ try {
|
||||||
);
|
);
|
||||||
$workflow->setConduitCredentials($credentials);
|
$workflow->setConduitCredentials($credentials);
|
||||||
|
|
||||||
|
$basic_user = $configuration_manager->getConfigFromAnySource(
|
||||||
|
'http.basicauth.user');
|
||||||
|
$basic_pass = $configuration_manager->getConfigFromAnySource(
|
||||||
|
'http.basicauth.pass');
|
||||||
|
|
||||||
|
$engine = id(new ArcanistConduitEngine())
|
||||||
|
->setConduitURI($conduit_uri)
|
||||||
|
->setConduitToken($conduit_token)
|
||||||
|
->setBasicAuthUser($basic_user)
|
||||||
|
->setBasicAuthPass($basic_pass);
|
||||||
|
|
||||||
|
if ($conduit_timeout) {
|
||||||
|
$engine->setConduitTimeout($conduit_timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
$workflow->setConduitEngine($engine);
|
||||||
|
|
||||||
if ($need_auth) {
|
if ($need_auth) {
|
||||||
if ((!$user_name || !$certificate) && (!$conduit_token)) {
|
if ((!$user_name || !$certificate) && (!$conduit_token)) {
|
||||||
$arc = 'arc';
|
$arc = 'arc';
|
||||||
|
@ -408,7 +434,7 @@ try {
|
||||||
fwrite(STDERR, phutil_console_format(
|
fwrite(STDERR, phutil_console_format(
|
||||||
"**%s** %s\n",
|
"**%s** %s\n",
|
||||||
pht('Usage Exception:'),
|
pht('Usage Exception:'),
|
||||||
$ex->getMessage()));
|
rtrim($ex->getMessage())));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($config) {
|
if ($config) {
|
||||||
|
|
|
@ -46,8 +46,17 @@ phutil_register_library_map(array(
|
||||||
'ArcanistBookmarkWorkflow' => 'workflow/ArcanistBookmarkWorkflow.php',
|
'ArcanistBookmarkWorkflow' => 'workflow/ArcanistBookmarkWorkflow.php',
|
||||||
'ArcanistBraceFormattingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistBraceFormattingXHPASTLinterRule.php',
|
'ArcanistBraceFormattingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistBraceFormattingXHPASTLinterRule.php',
|
||||||
'ArcanistBraceFormattingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistBraceFormattingXHPASTLinterRuleTestCase.php',
|
'ArcanistBraceFormattingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistBraceFormattingXHPASTLinterRuleTestCase.php',
|
||||||
|
'ArcanistBranchRef' => 'ref/ArcanistBranchRef.php',
|
||||||
'ArcanistBranchWorkflow' => 'workflow/ArcanistBranchWorkflow.php',
|
'ArcanistBranchWorkflow' => 'workflow/ArcanistBranchWorkflow.php',
|
||||||
'ArcanistBrowseWorkflow' => 'workflow/ArcanistBrowseWorkflow.php',
|
'ArcanistBrowseCommitHardpointLoader' => 'browse/loader/ArcanistBrowseCommitHardpointLoader.php',
|
||||||
|
'ArcanistBrowseCommitURIHardpointLoader' => 'browse/loader/ArcanistBrowseCommitURIHardpointLoader.php',
|
||||||
|
'ArcanistBrowseObjectNameURIHardpointLoader' => 'browse/loader/ArcanistBrowseObjectNameURIHardpointLoader.php',
|
||||||
|
'ArcanistBrowsePathURIHardpointLoader' => 'browse/loader/ArcanistBrowsePathURIHardpointLoader.php',
|
||||||
|
'ArcanistBrowseRef' => 'browse/ref/ArcanistBrowseRef.php',
|
||||||
|
'ArcanistBrowseRevisionURIHardpointLoader' => 'browse/loader/ArcanistBrowseRevisionURIHardpointLoader.php',
|
||||||
|
'ArcanistBrowseURIHardpointLoader' => 'browse/loader/ArcanistBrowseURIHardpointLoader.php',
|
||||||
|
'ArcanistBrowseURIRef' => 'browse/ref/ArcanistBrowseURIRef.php',
|
||||||
|
'ArcanistBrowseWorkflow' => 'browse/workflow/ArcanistBrowseWorkflow.php',
|
||||||
'ArcanistBuildPlanRef' => 'ref/ArcanistBuildPlanRef.php',
|
'ArcanistBuildPlanRef' => 'ref/ArcanistBuildPlanRef.php',
|
||||||
'ArcanistBuildRef' => 'ref/ArcanistBuildRef.php',
|
'ArcanistBuildRef' => 'ref/ArcanistBuildRef.php',
|
||||||
'ArcanistBundle' => 'parser/ArcanistBundle.php',
|
'ArcanistBundle' => 'parser/ArcanistBundle.php',
|
||||||
|
@ -84,12 +93,16 @@ phutil_register_library_map(array(
|
||||||
'ArcanistCommentSpacingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistCommentSpacingXHPASTLinterRule.php',
|
'ArcanistCommentSpacingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistCommentSpacingXHPASTLinterRule.php',
|
||||||
'ArcanistCommentStyleXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistCommentStyleXHPASTLinterRule.php',
|
'ArcanistCommentStyleXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistCommentStyleXHPASTLinterRule.php',
|
||||||
'ArcanistCommentStyleXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistCommentStyleXHPASTLinterRuleTestCase.php',
|
'ArcanistCommentStyleXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistCommentStyleXHPASTLinterRuleTestCase.php',
|
||||||
|
'ArcanistCommitRef' => 'ref/ArcanistCommitRef.php',
|
||||||
|
'ArcanistCommitUpstreamHardpointLoader' => 'loader/ArcanistCommitUpstreamHardpointLoader.php',
|
||||||
'ArcanistCommitWorkflow' => 'workflow/ArcanistCommitWorkflow.php',
|
'ArcanistCommitWorkflow' => 'workflow/ArcanistCommitWorkflow.php',
|
||||||
'ArcanistCompilerLintRenderer' => 'lint/renderer/ArcanistCompilerLintRenderer.php',
|
'ArcanistCompilerLintRenderer' => 'lint/renderer/ArcanistCompilerLintRenderer.php',
|
||||||
'ArcanistComposerLinter' => 'lint/linter/ArcanistComposerLinter.php',
|
'ArcanistComposerLinter' => 'lint/linter/ArcanistComposerLinter.php',
|
||||||
'ArcanistComprehensiveLintEngine' => 'lint/engine/ArcanistComprehensiveLintEngine.php',
|
'ArcanistComprehensiveLintEngine' => 'lint/engine/ArcanistComprehensiveLintEngine.php',
|
||||||
'ArcanistConcatenationOperatorXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistConcatenationOperatorXHPASTLinterRule.php',
|
'ArcanistConcatenationOperatorXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistConcatenationOperatorXHPASTLinterRule.php',
|
||||||
'ArcanistConcatenationOperatorXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistConcatenationOperatorXHPASTLinterRuleTestCase.php',
|
'ArcanistConcatenationOperatorXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistConcatenationOperatorXHPASTLinterRuleTestCase.php',
|
||||||
|
'ArcanistConduitCall' => 'conduit/ArcanistConduitCall.php',
|
||||||
|
'ArcanistConduitEngine' => 'conduit/ArcanistConduitEngine.php',
|
||||||
'ArcanistConfiguration' => 'configuration/ArcanistConfiguration.php',
|
'ArcanistConfiguration' => 'configuration/ArcanistConfiguration.php',
|
||||||
'ArcanistConfigurationDrivenLintEngine' => 'lint/engine/ArcanistConfigurationDrivenLintEngine.php',
|
'ArcanistConfigurationDrivenLintEngine' => 'lint/engine/ArcanistConfigurationDrivenLintEngine.php',
|
||||||
'ArcanistConfigurationDrivenUnitTestEngine' => 'unit/engine/ArcanistConfigurationDrivenUnitTestEngine.php',
|
'ArcanistConfigurationDrivenUnitTestEngine' => 'unit/engine/ArcanistConfigurationDrivenUnitTestEngine.php',
|
||||||
|
@ -168,7 +181,10 @@ phutil_register_library_map(array(
|
||||||
'ArcanistGeneratedLinterTestCase' => 'lint/linter/__tests__/ArcanistGeneratedLinterTestCase.php',
|
'ArcanistGeneratedLinterTestCase' => 'lint/linter/__tests__/ArcanistGeneratedLinterTestCase.php',
|
||||||
'ArcanistGetConfigWorkflow' => 'workflow/ArcanistGetConfigWorkflow.php',
|
'ArcanistGetConfigWorkflow' => 'workflow/ArcanistGetConfigWorkflow.php',
|
||||||
'ArcanistGitAPI' => 'repository/api/ArcanistGitAPI.php',
|
'ArcanistGitAPI' => 'repository/api/ArcanistGitAPI.php',
|
||||||
|
'ArcanistGitCommitMessageHardpointLoader' => 'loader/ArcanistGitCommitMessageHardpointLoader.php',
|
||||||
|
'ArcanistGitHardpointLoader' => 'loader/ArcanistGitHardpointLoader.php',
|
||||||
'ArcanistGitLandEngine' => 'land/ArcanistGitLandEngine.php',
|
'ArcanistGitLandEngine' => 'land/ArcanistGitLandEngine.php',
|
||||||
|
'ArcanistGitRevisionHardpointLoader' => 'loader/ArcanistGitRevisionHardpointLoader.php',
|
||||||
'ArcanistGitUpstreamPath' => 'repository/api/ArcanistGitUpstreamPath.php',
|
'ArcanistGitUpstreamPath' => 'repository/api/ArcanistGitUpstreamPath.php',
|
||||||
'ArcanistGlobalVariableXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistGlobalVariableXHPASTLinterRule.php',
|
'ArcanistGlobalVariableXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistGlobalVariableXHPASTLinterRule.php',
|
||||||
'ArcanistGlobalVariableXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistGlobalVariableXHPASTLinterRuleTestCase.php',
|
'ArcanistGlobalVariableXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistGlobalVariableXHPASTLinterRuleTestCase.php',
|
||||||
|
@ -178,6 +194,7 @@ phutil_register_library_map(array(
|
||||||
'ArcanistGoTestResultParserTestCase' => 'unit/parser/__tests__/ArcanistGoTestResultParserTestCase.php',
|
'ArcanistGoTestResultParserTestCase' => 'unit/parser/__tests__/ArcanistGoTestResultParserTestCase.php',
|
||||||
'ArcanistHLintLinter' => 'lint/linter/ArcanistHLintLinter.php',
|
'ArcanistHLintLinter' => 'lint/linter/ArcanistHLintLinter.php',
|
||||||
'ArcanistHLintLinterTestCase' => 'lint/linter/__tests__/ArcanistHLintLinterTestCase.php',
|
'ArcanistHLintLinterTestCase' => 'lint/linter/__tests__/ArcanistHLintLinterTestCase.php',
|
||||||
|
'ArcanistHardpointLoader' => 'loader/ArcanistHardpointLoader.php',
|
||||||
'ArcanistHelpWorkflow' => 'workflow/ArcanistHelpWorkflow.php',
|
'ArcanistHelpWorkflow' => 'workflow/ArcanistHelpWorkflow.php',
|
||||||
'ArcanistHexadecimalNumericScalarCasingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistHexadecimalNumericScalarCasingXHPASTLinterRule.php',
|
'ArcanistHexadecimalNumericScalarCasingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistHexadecimalNumericScalarCasingXHPASTLinterRule.php',
|
||||||
'ArcanistHexadecimalNumericScalarCasingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistHexadecimalNumericScalarCasingXHPASTLinterRuleTestCase.php',
|
'ArcanistHexadecimalNumericScalarCasingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistHexadecimalNumericScalarCasingXHPASTLinterRuleTestCase.php',
|
||||||
|
@ -254,10 +271,14 @@ phutil_register_library_map(array(
|
||||||
'ArcanistLowercaseFunctionsXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistLowercaseFunctionsXHPASTLinterRule.php',
|
'ArcanistLowercaseFunctionsXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistLowercaseFunctionsXHPASTLinterRule.php',
|
||||||
'ArcanistLowercaseFunctionsXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistLowercaseFunctionsXHPASTLinterRuleTestCase.php',
|
'ArcanistLowercaseFunctionsXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistLowercaseFunctionsXHPASTLinterRuleTestCase.php',
|
||||||
'ArcanistMercurialAPI' => 'repository/api/ArcanistMercurialAPI.php',
|
'ArcanistMercurialAPI' => 'repository/api/ArcanistMercurialAPI.php',
|
||||||
|
'ArcanistMercurialBranchCommitHardpointLoader' => 'loader/ArcanistMercurialBranchCommitHardpointLoader.php',
|
||||||
|
'ArcanistMercurialHardpointLoader' => 'loader/ArcanistMercurialHardpointLoader.php',
|
||||||
'ArcanistMercurialParser' => 'repository/parser/ArcanistMercurialParser.php',
|
'ArcanistMercurialParser' => 'repository/parser/ArcanistMercurialParser.php',
|
||||||
'ArcanistMercurialParserTestCase' => 'repository/parser/__tests__/ArcanistMercurialParserTestCase.php',
|
'ArcanistMercurialParserTestCase' => 'repository/parser/__tests__/ArcanistMercurialParserTestCase.php',
|
||||||
|
'ArcanistMercurialWorkingCopyCommitHardpointLoader' => 'loader/ArcanistMercurialWorkingCopyCommitHardpointLoader.php',
|
||||||
'ArcanistMergeConflictLinter' => 'lint/linter/ArcanistMergeConflictLinter.php',
|
'ArcanistMergeConflictLinter' => 'lint/linter/ArcanistMergeConflictLinter.php',
|
||||||
'ArcanistMergeConflictLinterTestCase' => 'lint/linter/__tests__/ArcanistMergeConflictLinterTestCase.php',
|
'ArcanistMergeConflictLinterTestCase' => 'lint/linter/__tests__/ArcanistMergeConflictLinterTestCase.php',
|
||||||
|
'ArcanistMessageRevisionHardpointLoader' => 'loader/ArcanistMessageRevisionHardpointLoader.php',
|
||||||
'ArcanistMissingLinterException' => 'lint/linter/exception/ArcanistMissingLinterException.php',
|
'ArcanistMissingLinterException' => 'lint/linter/exception/ArcanistMissingLinterException.php',
|
||||||
'ArcanistModifierOrderingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistModifierOrderingXHPASTLinterRule.php',
|
'ArcanistModifierOrderingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistModifierOrderingXHPASTLinterRule.php',
|
||||||
'ArcanistModifierOrderingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistModifierOrderingXHPASTLinterRuleTestCase.php',
|
'ArcanistModifierOrderingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistModifierOrderingXHPASTLinterRuleTestCase.php',
|
||||||
|
@ -322,9 +343,12 @@ phutil_register_library_map(array(
|
||||||
'ArcanistPyLintLinterTestCase' => 'lint/linter/__tests__/ArcanistPyLintLinterTestCase.php',
|
'ArcanistPyLintLinterTestCase' => 'lint/linter/__tests__/ArcanistPyLintLinterTestCase.php',
|
||||||
'ArcanistRaggedClassTreeEdgeXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistRaggedClassTreeEdgeXHPASTLinterRule.php',
|
'ArcanistRaggedClassTreeEdgeXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistRaggedClassTreeEdgeXHPASTLinterRule.php',
|
||||||
'ArcanistRaggedClassTreeEdgeXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistRaggedClassTreeEdgeXHPASTLinterRuleTestCase.php',
|
'ArcanistRaggedClassTreeEdgeXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistRaggedClassTreeEdgeXHPASTLinterRuleTestCase.php',
|
||||||
|
'ArcanistRef' => 'ref/ArcanistRef.php',
|
||||||
|
'ArcanistRefQuery' => 'ref/ArcanistRefQuery.php',
|
||||||
'ArcanistRepositoryAPI' => 'repository/api/ArcanistRepositoryAPI.php',
|
'ArcanistRepositoryAPI' => 'repository/api/ArcanistRepositoryAPI.php',
|
||||||
'ArcanistRepositoryAPIMiscTestCase' => 'repository/api/__tests__/ArcanistRepositoryAPIMiscTestCase.php',
|
'ArcanistRepositoryAPIMiscTestCase' => 'repository/api/__tests__/ArcanistRepositoryAPIMiscTestCase.php',
|
||||||
'ArcanistRepositoryAPIStateTestCase' => 'repository/api/__tests__/ArcanistRepositoryAPIStateTestCase.php',
|
'ArcanistRepositoryAPIStateTestCase' => 'repository/api/__tests__/ArcanistRepositoryAPIStateTestCase.php',
|
||||||
|
'ArcanistRepositoryRef' => 'ref/ArcanistRepositoryRef.php',
|
||||||
'ArcanistReusedAsIteratorXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistReusedAsIteratorXHPASTLinterRule.php',
|
'ArcanistReusedAsIteratorXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistReusedAsIteratorXHPASTLinterRule.php',
|
||||||
'ArcanistReusedAsIteratorXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistReusedAsIteratorXHPASTLinterRuleTestCase.php',
|
'ArcanistReusedAsIteratorXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistReusedAsIteratorXHPASTLinterRuleTestCase.php',
|
||||||
'ArcanistReusedIteratorReferenceXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistReusedIteratorReferenceXHPASTLinterRule.php',
|
'ArcanistReusedIteratorReferenceXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistReusedIteratorReferenceXHPASTLinterRule.php',
|
||||||
|
@ -332,6 +356,8 @@ phutil_register_library_map(array(
|
||||||
'ArcanistReusedIteratorXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistReusedIteratorXHPASTLinterRule.php',
|
'ArcanistReusedIteratorXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistReusedIteratorXHPASTLinterRule.php',
|
||||||
'ArcanistReusedIteratorXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistReusedIteratorXHPASTLinterRuleTestCase.php',
|
'ArcanistReusedIteratorXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistReusedIteratorXHPASTLinterRuleTestCase.php',
|
||||||
'ArcanistRevertWorkflow' => 'workflow/ArcanistRevertWorkflow.php',
|
'ArcanistRevertWorkflow' => 'workflow/ArcanistRevertWorkflow.php',
|
||||||
|
'ArcanistRevisionRef' => 'ref/ArcanistRevisionRef.php',
|
||||||
|
'ArcanistRevisionRefSource' => 'ref/ArcanistRevisionRefSource.php',
|
||||||
'ArcanistRuboCopLinter' => 'lint/linter/ArcanistRuboCopLinter.php',
|
'ArcanistRuboCopLinter' => 'lint/linter/ArcanistRuboCopLinter.php',
|
||||||
'ArcanistRuboCopLinterTestCase' => 'lint/linter/__tests__/ArcanistRuboCopLinterTestCase.php',
|
'ArcanistRuboCopLinterTestCase' => 'lint/linter/__tests__/ArcanistRuboCopLinterTestCase.php',
|
||||||
'ArcanistRubyLinter' => 'lint/linter/ArcanistRubyLinter.php',
|
'ArcanistRubyLinter' => 'lint/linter/ArcanistRubyLinter.php',
|
||||||
|
@ -344,6 +370,7 @@ phutil_register_library_map(array(
|
||||||
'ArcanistSemicolonSpacingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistSemicolonSpacingXHPASTLinterRule.php',
|
'ArcanistSemicolonSpacingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistSemicolonSpacingXHPASTLinterRule.php',
|
||||||
'ArcanistSemicolonSpacingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistSemicolonSpacingXHPASTLinterRuleTestCase.php',
|
'ArcanistSemicolonSpacingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistSemicolonSpacingXHPASTLinterRuleTestCase.php',
|
||||||
'ArcanistSetConfigWorkflow' => 'workflow/ArcanistSetConfigWorkflow.php',
|
'ArcanistSetConfigWorkflow' => 'workflow/ArcanistSetConfigWorkflow.php',
|
||||||
|
'ArcanistSetting' => 'configuration/ArcanistSetting.php',
|
||||||
'ArcanistSettings' => 'configuration/ArcanistSettings.php',
|
'ArcanistSettings' => 'configuration/ArcanistSettings.php',
|
||||||
'ArcanistShellCompleteWorkflow' => 'workflow/ArcanistShellCompleteWorkflow.php',
|
'ArcanistShellCompleteWorkflow' => 'workflow/ArcanistShellCompleteWorkflow.php',
|
||||||
'ArcanistSingleLintEngine' => 'lint/engine/ArcanistSingleLintEngine.php',
|
'ArcanistSingleLintEngine' => 'lint/engine/ArcanistSingleLintEngine.php',
|
||||||
|
@ -414,6 +441,7 @@ phutil_register_library_map(array(
|
||||||
'ArcanistWhichWorkflow' => 'workflow/ArcanistWhichWorkflow.php',
|
'ArcanistWhichWorkflow' => 'workflow/ArcanistWhichWorkflow.php',
|
||||||
'ArcanistWorkflow' => 'workflow/ArcanistWorkflow.php',
|
'ArcanistWorkflow' => 'workflow/ArcanistWorkflow.php',
|
||||||
'ArcanistWorkingCopyIdentity' => 'workingcopyidentity/ArcanistWorkingCopyIdentity.php',
|
'ArcanistWorkingCopyIdentity' => 'workingcopyidentity/ArcanistWorkingCopyIdentity.php',
|
||||||
|
'ArcanistWorkingCopyStateRef' => 'ref/ArcanistWorkingCopyStateRef.php',
|
||||||
'ArcanistXHPASTLintNamingHook' => 'lint/linter/xhpast/ArcanistXHPASTLintNamingHook.php',
|
'ArcanistXHPASTLintNamingHook' => 'lint/linter/xhpast/ArcanistXHPASTLintNamingHook.php',
|
||||||
'ArcanistXHPASTLintNamingHookTestCase' => 'lint/linter/xhpast/__tests__/ArcanistXHPASTLintNamingHookTestCase.php',
|
'ArcanistXHPASTLintNamingHookTestCase' => 'lint/linter/xhpast/__tests__/ArcanistXHPASTLintNamingHookTestCase.php',
|
||||||
'ArcanistXHPASTLintSwitchHook' => 'lint/linter/xhpast/ArcanistXHPASTLintSwitchHook.php',
|
'ArcanistXHPASTLintSwitchHook' => 'lint/linter/xhpast/ArcanistXHPASTLintSwitchHook.php',
|
||||||
|
@ -916,7 +944,16 @@ phutil_register_library_map(array(
|
||||||
'ArcanistBookmarkWorkflow' => 'ArcanistFeatureWorkflow',
|
'ArcanistBookmarkWorkflow' => 'ArcanistFeatureWorkflow',
|
||||||
'ArcanistBraceFormattingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
'ArcanistBraceFormattingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||||
'ArcanistBraceFormattingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
'ArcanistBraceFormattingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||||
|
'ArcanistBranchRef' => 'ArcanistRef',
|
||||||
'ArcanistBranchWorkflow' => 'ArcanistFeatureWorkflow',
|
'ArcanistBranchWorkflow' => 'ArcanistFeatureWorkflow',
|
||||||
|
'ArcanistBrowseCommitHardpointLoader' => 'ArcanistHardpointLoader',
|
||||||
|
'ArcanistBrowseCommitURIHardpointLoader' => 'ArcanistBrowseURIHardpointLoader',
|
||||||
|
'ArcanistBrowseObjectNameURIHardpointLoader' => 'ArcanistBrowseURIHardpointLoader',
|
||||||
|
'ArcanistBrowsePathURIHardpointLoader' => 'ArcanistBrowseURIHardpointLoader',
|
||||||
|
'ArcanistBrowseRef' => 'ArcanistRef',
|
||||||
|
'ArcanistBrowseRevisionURIHardpointLoader' => 'ArcanistBrowseURIHardpointLoader',
|
||||||
|
'ArcanistBrowseURIHardpointLoader' => 'ArcanistHardpointLoader',
|
||||||
|
'ArcanistBrowseURIRef' => 'ArcanistRef',
|
||||||
'ArcanistBrowseWorkflow' => 'ArcanistWorkflow',
|
'ArcanistBrowseWorkflow' => 'ArcanistWorkflow',
|
||||||
'ArcanistBuildPlanRef' => 'Phobject',
|
'ArcanistBuildPlanRef' => 'Phobject',
|
||||||
'ArcanistBuildRef' => 'Phobject',
|
'ArcanistBuildRef' => 'Phobject',
|
||||||
|
@ -954,12 +991,16 @@ phutil_register_library_map(array(
|
||||||
'ArcanistCommentSpacingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
'ArcanistCommentSpacingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||||
'ArcanistCommentStyleXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
'ArcanistCommentStyleXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||||
'ArcanistCommentStyleXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
'ArcanistCommentStyleXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||||
|
'ArcanistCommitRef' => 'ArcanistRef',
|
||||||
|
'ArcanistCommitUpstreamHardpointLoader' => 'ArcanistHardpointLoader',
|
||||||
'ArcanistCommitWorkflow' => 'ArcanistWorkflow',
|
'ArcanistCommitWorkflow' => 'ArcanistWorkflow',
|
||||||
'ArcanistCompilerLintRenderer' => 'ArcanistLintRenderer',
|
'ArcanistCompilerLintRenderer' => 'ArcanistLintRenderer',
|
||||||
'ArcanistComposerLinter' => 'ArcanistLinter',
|
'ArcanistComposerLinter' => 'ArcanistLinter',
|
||||||
'ArcanistComprehensiveLintEngine' => 'ArcanistLintEngine',
|
'ArcanistComprehensiveLintEngine' => 'ArcanistLintEngine',
|
||||||
'ArcanistConcatenationOperatorXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
'ArcanistConcatenationOperatorXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||||
'ArcanistConcatenationOperatorXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
'ArcanistConcatenationOperatorXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||||
|
'ArcanistConduitCall' => 'Phobject',
|
||||||
|
'ArcanistConduitEngine' => 'Phobject',
|
||||||
'ArcanistConfiguration' => 'Phobject',
|
'ArcanistConfiguration' => 'Phobject',
|
||||||
'ArcanistConfigurationDrivenLintEngine' => 'ArcanistLintEngine',
|
'ArcanistConfigurationDrivenLintEngine' => 'ArcanistLintEngine',
|
||||||
'ArcanistConfigurationDrivenUnitTestEngine' => 'ArcanistUnitTestEngine',
|
'ArcanistConfigurationDrivenUnitTestEngine' => 'ArcanistUnitTestEngine',
|
||||||
|
@ -1038,7 +1079,10 @@ phutil_register_library_map(array(
|
||||||
'ArcanistGeneratedLinterTestCase' => 'ArcanistLinterTestCase',
|
'ArcanistGeneratedLinterTestCase' => 'ArcanistLinterTestCase',
|
||||||
'ArcanistGetConfigWorkflow' => 'ArcanistWorkflow',
|
'ArcanistGetConfigWorkflow' => 'ArcanistWorkflow',
|
||||||
'ArcanistGitAPI' => 'ArcanistRepositoryAPI',
|
'ArcanistGitAPI' => 'ArcanistRepositoryAPI',
|
||||||
|
'ArcanistGitCommitMessageHardpointLoader' => 'ArcanistGitHardpointLoader',
|
||||||
|
'ArcanistGitHardpointLoader' => 'ArcanistHardpointLoader',
|
||||||
'ArcanistGitLandEngine' => 'ArcanistLandEngine',
|
'ArcanistGitLandEngine' => 'ArcanistLandEngine',
|
||||||
|
'ArcanistGitRevisionHardpointLoader' => 'ArcanistGitHardpointLoader',
|
||||||
'ArcanistGitUpstreamPath' => 'Phobject',
|
'ArcanistGitUpstreamPath' => 'Phobject',
|
||||||
'ArcanistGlobalVariableXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
'ArcanistGlobalVariableXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||||
'ArcanistGlobalVariableXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
'ArcanistGlobalVariableXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||||
|
@ -1048,6 +1092,7 @@ phutil_register_library_map(array(
|
||||||
'ArcanistGoTestResultParserTestCase' => 'PhutilTestCase',
|
'ArcanistGoTestResultParserTestCase' => 'PhutilTestCase',
|
||||||
'ArcanistHLintLinter' => 'ArcanistExternalLinter',
|
'ArcanistHLintLinter' => 'ArcanistExternalLinter',
|
||||||
'ArcanistHLintLinterTestCase' => 'ArcanistExternalLinterTestCase',
|
'ArcanistHLintLinterTestCase' => 'ArcanistExternalLinterTestCase',
|
||||||
|
'ArcanistHardpointLoader' => 'Phobject',
|
||||||
'ArcanistHelpWorkflow' => 'ArcanistWorkflow',
|
'ArcanistHelpWorkflow' => 'ArcanistWorkflow',
|
||||||
'ArcanistHexadecimalNumericScalarCasingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
'ArcanistHexadecimalNumericScalarCasingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||||
'ArcanistHexadecimalNumericScalarCasingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
'ArcanistHexadecimalNumericScalarCasingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||||
|
@ -1124,10 +1169,14 @@ phutil_register_library_map(array(
|
||||||
'ArcanistLowercaseFunctionsXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
'ArcanistLowercaseFunctionsXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||||
'ArcanistLowercaseFunctionsXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
'ArcanistLowercaseFunctionsXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||||
'ArcanistMercurialAPI' => 'ArcanistRepositoryAPI',
|
'ArcanistMercurialAPI' => 'ArcanistRepositoryAPI',
|
||||||
|
'ArcanistMercurialBranchCommitHardpointLoader' => 'ArcanistMercurialHardpointLoader',
|
||||||
|
'ArcanistMercurialHardpointLoader' => 'ArcanistHardpointLoader',
|
||||||
'ArcanistMercurialParser' => 'Phobject',
|
'ArcanistMercurialParser' => 'Phobject',
|
||||||
'ArcanistMercurialParserTestCase' => 'PhutilTestCase',
|
'ArcanistMercurialParserTestCase' => 'PhutilTestCase',
|
||||||
|
'ArcanistMercurialWorkingCopyCommitHardpointLoader' => 'ArcanistMercurialHardpointLoader',
|
||||||
'ArcanistMergeConflictLinter' => 'ArcanistLinter',
|
'ArcanistMergeConflictLinter' => 'ArcanistLinter',
|
||||||
'ArcanistMergeConflictLinterTestCase' => 'ArcanistLinterTestCase',
|
'ArcanistMergeConflictLinterTestCase' => 'ArcanistLinterTestCase',
|
||||||
|
'ArcanistMessageRevisionHardpointLoader' => 'ArcanistHardpointLoader',
|
||||||
'ArcanistMissingLinterException' => 'Exception',
|
'ArcanistMissingLinterException' => 'Exception',
|
||||||
'ArcanistModifierOrderingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
'ArcanistModifierOrderingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||||
'ArcanistModifierOrderingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
'ArcanistModifierOrderingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||||
|
@ -1192,9 +1241,12 @@ phutil_register_library_map(array(
|
||||||
'ArcanistPyLintLinterTestCase' => 'ArcanistExternalLinterTestCase',
|
'ArcanistPyLintLinterTestCase' => 'ArcanistExternalLinterTestCase',
|
||||||
'ArcanistRaggedClassTreeEdgeXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
'ArcanistRaggedClassTreeEdgeXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||||
'ArcanistRaggedClassTreeEdgeXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
'ArcanistRaggedClassTreeEdgeXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||||
|
'ArcanistRef' => 'Phobject',
|
||||||
|
'ArcanistRefQuery' => 'Phobject',
|
||||||
'ArcanistRepositoryAPI' => 'Phobject',
|
'ArcanistRepositoryAPI' => 'Phobject',
|
||||||
'ArcanistRepositoryAPIMiscTestCase' => 'PhutilTestCase',
|
'ArcanistRepositoryAPIMiscTestCase' => 'PhutilTestCase',
|
||||||
'ArcanistRepositoryAPIStateTestCase' => 'PhutilTestCase',
|
'ArcanistRepositoryAPIStateTestCase' => 'PhutilTestCase',
|
||||||
|
'ArcanistRepositoryRef' => 'ArcanistRef',
|
||||||
'ArcanistReusedAsIteratorXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
'ArcanistReusedAsIteratorXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||||
'ArcanistReusedAsIteratorXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
'ArcanistReusedAsIteratorXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||||
'ArcanistReusedIteratorReferenceXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
'ArcanistReusedIteratorReferenceXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||||
|
@ -1202,6 +1254,8 @@ phutil_register_library_map(array(
|
||||||
'ArcanistReusedIteratorXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
'ArcanistReusedIteratorXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||||
'ArcanistReusedIteratorXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
'ArcanistReusedIteratorXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||||
'ArcanistRevertWorkflow' => 'ArcanistWorkflow',
|
'ArcanistRevertWorkflow' => 'ArcanistWorkflow',
|
||||||
|
'ArcanistRevisionRef' => 'ArcanistRef',
|
||||||
|
'ArcanistRevisionRefSource' => 'Phobject',
|
||||||
'ArcanistRuboCopLinter' => 'ArcanistExternalLinter',
|
'ArcanistRuboCopLinter' => 'ArcanistExternalLinter',
|
||||||
'ArcanistRuboCopLinterTestCase' => 'ArcanistExternalLinterTestCase',
|
'ArcanistRuboCopLinterTestCase' => 'ArcanistExternalLinterTestCase',
|
||||||
'ArcanistRubyLinter' => 'ArcanistExternalLinter',
|
'ArcanistRubyLinter' => 'ArcanistExternalLinter',
|
||||||
|
@ -1214,6 +1268,7 @@ phutil_register_library_map(array(
|
||||||
'ArcanistSemicolonSpacingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
'ArcanistSemicolonSpacingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||||
'ArcanistSemicolonSpacingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
'ArcanistSemicolonSpacingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||||
'ArcanistSetConfigWorkflow' => 'ArcanistWorkflow',
|
'ArcanistSetConfigWorkflow' => 'ArcanistWorkflow',
|
||||||
|
'ArcanistSetting' => 'Phobject',
|
||||||
'ArcanistSettings' => 'Phobject',
|
'ArcanistSettings' => 'Phobject',
|
||||||
'ArcanistShellCompleteWorkflow' => 'ArcanistWorkflow',
|
'ArcanistShellCompleteWorkflow' => 'ArcanistWorkflow',
|
||||||
'ArcanistSingleLintEngine' => 'ArcanistLintEngine',
|
'ArcanistSingleLintEngine' => 'ArcanistLintEngine',
|
||||||
|
@ -1284,6 +1339,7 @@ phutil_register_library_map(array(
|
||||||
'ArcanistWhichWorkflow' => 'ArcanistWorkflow',
|
'ArcanistWhichWorkflow' => 'ArcanistWorkflow',
|
||||||
'ArcanistWorkflow' => 'Phobject',
|
'ArcanistWorkflow' => 'Phobject',
|
||||||
'ArcanistWorkingCopyIdentity' => 'Phobject',
|
'ArcanistWorkingCopyIdentity' => 'Phobject',
|
||||||
|
'ArcanistWorkingCopyStateRef' => 'ArcanistRef',
|
||||||
'ArcanistXHPASTLintNamingHook' => 'Phobject',
|
'ArcanistXHPASTLintNamingHook' => 'Phobject',
|
||||||
'ArcanistXHPASTLintNamingHookTestCase' => 'PhutilTestCase',
|
'ArcanistXHPASTLintNamingHookTestCase' => 'PhutilTestCase',
|
||||||
'ArcanistXHPASTLintSwitchHook' => 'Phobject',
|
'ArcanistXHPASTLintSwitchHook' => 'Phobject',
|
||||||
|
|
80
src/browse/loader/ArcanistBrowseCommitHardpointLoader.php
Normal file
80
src/browse/loader/ArcanistBrowseCommitHardpointLoader.php
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ArcanistBrowseCommitHardpointLoader
|
||||||
|
extends ArcanistHardpointLoader {
|
||||||
|
|
||||||
|
const LOADERKEY = 'browse.ref.commit';
|
||||||
|
|
||||||
|
public function canLoadRepositoryAPI(ArcanistRepositoryAPI $api) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canLoadRef(ArcanistRef $ref) {
|
||||||
|
return ($ref instanceof ArcanistBrowseRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canLoadHardpoint(ArcanistRef $ref, $hardpoint) {
|
||||||
|
return ($hardpoint == 'commitRefs');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function loadHardpoints(array $refs, $hardpoint) {
|
||||||
|
$query = $this->getQuery();
|
||||||
|
|
||||||
|
$api = $query->getRepositoryAPI();
|
||||||
|
if (!$api) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$repository_ref = $query->getRepositoryRef();
|
||||||
|
if (!$repository_ref) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
$repository_phid = $repository_ref->getPHID();
|
||||||
|
|
||||||
|
$commit_map = array();
|
||||||
|
foreach ($refs as $key => $ref) {
|
||||||
|
$token = $ref->getToken();
|
||||||
|
|
||||||
|
if ($token === '.') {
|
||||||
|
// Git resolves "." like HEAD, but we want to treat it as "browse the
|
||||||
|
// current directory" instead in all cases.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always resolve the empty token; top-level loaders filter out
|
||||||
|
// irrelevant tokens before this stage.
|
||||||
|
if ($token === null) {
|
||||||
|
$token = $api->getHeadCommit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: We should pull a full commit ref out of the API as soon as it
|
||||||
|
// is able to provide them. In particular, we currently miss Git tree
|
||||||
|
// hashes which reduces the accuracy of lookups.
|
||||||
|
|
||||||
|
try {
|
||||||
|
$commit = $api->getCanonicalRevisionName($token);
|
||||||
|
if ($commit) {
|
||||||
|
$commit_map[$commit][] = $key;
|
||||||
|
}
|
||||||
|
} catch (Exception $ex) {
|
||||||
|
// Ignore anything we can't resolve.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$commit_map) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$results = array();
|
||||||
|
foreach ($commit_map as $commit_identifier => $ref_keys) {
|
||||||
|
foreach ($ref_keys as $key) {
|
||||||
|
$commit_ref = id(new ArcanistCommitRef())
|
||||||
|
->setCommitHash($commit_identifier);
|
||||||
|
$results[$key][] = $commit_ref;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
92
src/browse/loader/ArcanistBrowseCommitURIHardpointLoader.php
Normal file
92
src/browse/loader/ArcanistBrowseCommitURIHardpointLoader.php
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ArcanistBrowseCommitURIHardpointLoader
|
||||||
|
extends ArcanistBrowseURIHardpointLoader {
|
||||||
|
|
||||||
|
const LOADERKEY = 'browse.uri.commit';
|
||||||
|
const BROWSETYPE = 'commit';
|
||||||
|
|
||||||
|
public function willLoadBrowseURIRefs(array $refs) {
|
||||||
|
$refs = $this->getRefsWithSupportedTypes($refs);
|
||||||
|
|
||||||
|
if (!$refs) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = $this->getQuery();
|
||||||
|
|
||||||
|
$working_ref = $query->getWorkingCopyRef();
|
||||||
|
if (!$working_ref) {
|
||||||
|
// If we aren't in a working copy, don't warn about this.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$repository_ref = $this->getQuery()->getRepositoryRef();
|
||||||
|
if (!$repository_ref) {
|
||||||
|
echo pht(
|
||||||
|
'NO REPOSITORY: Unable to determine which repository this working '.
|
||||||
|
'copy belongs to, so arguments can not be resolved as commits. Use '.
|
||||||
|
'"%s" to understand how repositories are resolved.',
|
||||||
|
'arc which');
|
||||||
|
echo "\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function loadHardpoints(array $refs, $hardpoint) {
|
||||||
|
$query = $this->getQuery();
|
||||||
|
|
||||||
|
$api = $query->getRepositoryAPI();
|
||||||
|
if (!$api) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$repository_ref = $query->getRepositoryRef();
|
||||||
|
if (!$repository_ref) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$refs = $this->getRefsWithSupportedTypes($refs);
|
||||||
|
if (!$refs) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->newQuery($refs)
|
||||||
|
->needHardpoints(
|
||||||
|
array(
|
||||||
|
'commitRefs',
|
||||||
|
))
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$commit_refs = array();
|
||||||
|
foreach ($refs as $key => $ref) {
|
||||||
|
foreach ($ref->getCommitRefs() as $commit_ref) {
|
||||||
|
$commit_refs[] = $commit_ref;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->newQuery($commit_refs)
|
||||||
|
->needHardpoints(
|
||||||
|
array(
|
||||||
|
'upstream',
|
||||||
|
))
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$results = array();
|
||||||
|
foreach ($refs as $key => $ref) {
|
||||||
|
$commit_refs = $ref->getCommitRefs();
|
||||||
|
foreach ($commit_refs as $commit_ref) {
|
||||||
|
$uri = $commit_ref->getURI();
|
||||||
|
if ($uri !== null) {
|
||||||
|
$results[$key][] = id(new ArcanistBrowseURIRef())
|
||||||
|
->setURI($uri)
|
||||||
|
->setType(self::BROWSETYPE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ArcanistBrowseObjectNameURIHardpointLoader
|
||||||
|
extends ArcanistBrowseURIHardpointLoader {
|
||||||
|
|
||||||
|
const LOADERKEY = 'browse.uri.name';
|
||||||
|
const BROWSETYPE = 'object';
|
||||||
|
|
||||||
|
public function loadHardpoints(array $refs, $hardpoint) {
|
||||||
|
$refs = $this->getRefsWithSupportedTypes($refs);
|
||||||
|
|
||||||
|
$name_map = array();
|
||||||
|
foreach ($refs as $key => $ref) {
|
||||||
|
$token = $ref->getToken();
|
||||||
|
if (!strlen($token)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$name_map[$key] = $token;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$name_map) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$objects = $this->resolveCall(
|
||||||
|
'phid.lookup',
|
||||||
|
array(
|
||||||
|
'names' => $name_map,
|
||||||
|
));
|
||||||
|
|
||||||
|
$result = array();
|
||||||
|
|
||||||
|
$reverse_map = array_flip($name_map);
|
||||||
|
foreach ($objects as $name => $object) {
|
||||||
|
$key = idx($reverse_map, $name);
|
||||||
|
if ($key === null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$uri = idx($object, 'uri');
|
||||||
|
if (!strlen($uri)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result[$key][] = id(new ArcanistBrowseURIRef())
|
||||||
|
->setURI($object['uri'])
|
||||||
|
->setType('object');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
132
src/browse/loader/ArcanistBrowsePathURIHardpointLoader.php
Normal file
132
src/browse/loader/ArcanistBrowsePathURIHardpointLoader.php
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ArcanistBrowsePathURIHardpointLoader
|
||||||
|
extends ArcanistBrowseURIHardpointLoader {
|
||||||
|
|
||||||
|
const LOADERKEY = 'browse.uri.path';
|
||||||
|
const BROWSETYPE = 'path';
|
||||||
|
|
||||||
|
public function willLoadBrowseURIRefs(array $refs) {
|
||||||
|
$refs = $this->getRefsWithSupportedTypes($refs);
|
||||||
|
if (!$refs) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = $this->getQuery();
|
||||||
|
|
||||||
|
$working_ref = $query->getWorkingCopyRef();
|
||||||
|
if (!$working_ref) {
|
||||||
|
echo pht(
|
||||||
|
'NO WORKING COPY: The current directory is not a repository '.
|
||||||
|
'working copy, so arguments can not be resolved as paths. Run '.
|
||||||
|
'this command inside a working copy to resolve paths.');
|
||||||
|
echo "\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$repository_ref = $query->getRepositoryRef();
|
||||||
|
if (!$repository_ref) {
|
||||||
|
echo pht(
|
||||||
|
'NO REPOSITORY: Unable to determine which repository this working '.
|
||||||
|
'copy belongs to, so arguments can not be resolved as paths. Use '.
|
||||||
|
'"%s" to understand how repositories are resolved.',
|
||||||
|
'arc which');
|
||||||
|
echo "\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function didFailToLoadBrowseURIRefs(array $refs) {
|
||||||
|
$refs = $this->getRefsWithSupportedTypes($refs);
|
||||||
|
if (!$refs) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = $this->getQuery();
|
||||||
|
|
||||||
|
$working_ref = $query->getWorkingCopyRef();
|
||||||
|
if (!$working_ref) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$repository_ref = $query->getRepositoryRef();
|
||||||
|
if (!$repository_ref) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo pht(
|
||||||
|
'Use "--types path" to force arguments to be interpreted as paths.');
|
||||||
|
echo "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function loadHardpoints(array $refs, $hardpoint) {
|
||||||
|
$query = $this->getQuery();
|
||||||
|
|
||||||
|
$working_ref = $query->getWorkingCopyRef();
|
||||||
|
if (!$working_ref) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$repository_ref = $query->getRepositoryRef();
|
||||||
|
if (!$repository_ref) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$refs = $this->getRefsWithSupportedTypes($refs);
|
||||||
|
$project_root = $working_ref->getRootDirectory();
|
||||||
|
|
||||||
|
$results = array();
|
||||||
|
foreach ($refs as $key => $ref) {
|
||||||
|
$is_path = $ref->hasType(self::BROWSETYPE);
|
||||||
|
|
||||||
|
$path = $ref->getToken();
|
||||||
|
if ($path === null) {
|
||||||
|
// If we're explicitly resolving no arguments as a path, treat it
|
||||||
|
// as the current working directory.
|
||||||
|
if ($is_path) {
|
||||||
|
$path = '.';
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$lines = null;
|
||||||
|
$parts = explode(':', $path);
|
||||||
|
if (count($parts) > 1) {
|
||||||
|
$lines = array_pop($parts);
|
||||||
|
}
|
||||||
|
$path = implode(':', $parts);
|
||||||
|
|
||||||
|
$full_path = Filesystem::resolvePath($path);
|
||||||
|
|
||||||
|
if (!Filesystem::pathExists($full_path)) {
|
||||||
|
if (!$is_path) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($full_path == $project_root) {
|
||||||
|
$path = '';
|
||||||
|
} else {
|
||||||
|
$path = Filesystem::readablePath($full_path, $project_root);
|
||||||
|
}
|
||||||
|
|
||||||
|
$params = array(
|
||||||
|
'path' => $path,
|
||||||
|
'lines' => $lines,
|
||||||
|
'branch' => $ref->getBranch(),
|
||||||
|
);
|
||||||
|
|
||||||
|
$uri = $repository_ref->newBrowseURI($params);
|
||||||
|
|
||||||
|
$results[$key][] = id(new ArcanistBrowseURIRef())
|
||||||
|
->setURI($uri)
|
||||||
|
->setType(self::BROWSETYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ArcanistBrowseRevisionURIHardpointLoader
|
||||||
|
extends ArcanistBrowseURIHardpointLoader {
|
||||||
|
|
||||||
|
const LOADERKEY = 'browse.uri.revision';
|
||||||
|
const BROWSETYPE = 'revision';
|
||||||
|
|
||||||
|
public function loadHardpoints(array $refs, $hardpoint) {
|
||||||
|
$query = $this->getQuery();
|
||||||
|
|
||||||
|
$working_ref = $query->getWorkingCopyRef();
|
||||||
|
if (!$working_ref) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$repository_ref = $query->getRepositoryRef();
|
||||||
|
if (!$repository_ref) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$refs = $this->getRefsWithSupportedTypes($refs);
|
||||||
|
if (!$refs) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->newQuery($refs)
|
||||||
|
->needHardpoints(
|
||||||
|
array(
|
||||||
|
'commitRefs',
|
||||||
|
))
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$states = array();
|
||||||
|
$map = array();
|
||||||
|
foreach ($refs as $key => $ref) {
|
||||||
|
foreach ($ref->getCommitRefs() as $commit_ref) {
|
||||||
|
$hash = $commit_ref->getCommitHash();
|
||||||
|
$states[$hash] = id(clone $working_ref)
|
||||||
|
->setCommitRef($commit_ref);
|
||||||
|
$map[$hash][] = $key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$states) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->newQuery($states)
|
||||||
|
->needHardpoints(
|
||||||
|
array(
|
||||||
|
'revisionRefs',
|
||||||
|
))
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$results = array();
|
||||||
|
foreach ($states as $hash => $state) {
|
||||||
|
foreach ($state->getRevisionRefs() as $revision) {
|
||||||
|
if ($revision->isClosed()) {
|
||||||
|
// Don't resolve closed revisions.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$uri = $revision->getURI();
|
||||||
|
|
||||||
|
foreach ($map[$hash] as $key) {
|
||||||
|
$results[$key][] = id(new ArcanistBrowseURIRef())
|
||||||
|
->setURI($uri)
|
||||||
|
->setType(self::BROWSETYPE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
55
src/browse/loader/ArcanistBrowseURIHardpointLoader.php
Normal file
55
src/browse/loader/ArcanistBrowseURIHardpointLoader.php
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class ArcanistBrowseURIHardpointLoader
|
||||||
|
extends ArcanistHardpointLoader {
|
||||||
|
|
||||||
|
public function getSupportedBrowseType() {
|
||||||
|
return $this->getPhobjectClassConstant('BROWSETYPE', 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canLoadRepositoryAPI(ArcanistRepositoryAPI $api) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canLoadRef(ArcanistRef $ref) {
|
||||||
|
return ($ref instanceof ArcanistBrowseRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canLoadHardpoint(ArcanistRef $ref, $hardpoint) {
|
||||||
|
return ($hardpoint == 'uris');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function willLoadBrowseURIRefs(array $refs) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function didFailToLoadBrowseURIRefs(array $refs) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRefsWithSupportedTypes(array $refs) {
|
||||||
|
$type = $this->getSupportedBrowseType();
|
||||||
|
|
||||||
|
foreach ($refs as $key => $ref) {
|
||||||
|
if ($ref->isUntyped()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($ref->hasType($type)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($refs[$key]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $refs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getAllBrowseLoaders() {
|
||||||
|
return id(new PhutilClassMapQuery())
|
||||||
|
->setAncestorClass(__CLASS__)
|
||||||
|
->setUniqueMethod('getLoaderKey')
|
||||||
|
->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
72
src/browse/ref/ArcanistBrowseRef.php
Normal file
72
src/browse/ref/ArcanistBrowseRef.php
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ArcanistBrowseRef
|
||||||
|
extends ArcanistRef {
|
||||||
|
|
||||||
|
private $token;
|
||||||
|
private $types;
|
||||||
|
private $branch;
|
||||||
|
|
||||||
|
public function getRefIdentifier() {
|
||||||
|
return pht('Browse Query "%s"', $this->getToken());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function defineHardpoints() {
|
||||||
|
return array(
|
||||||
|
'commitRefs' => array(
|
||||||
|
'type' => 'ArcanistCommitRef',
|
||||||
|
'vector' => true,
|
||||||
|
),
|
||||||
|
'uris' => array(
|
||||||
|
'type' => 'ArcanistBrowseURIRef',
|
||||||
|
'vector' => true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setToken($token) {
|
||||||
|
$this->token = $token;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getToken() {
|
||||||
|
return $this->token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setTypes(array $types) {
|
||||||
|
$this->types = $types;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTypes() {
|
||||||
|
return $this->types;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasType($type) {
|
||||||
|
$map = $this->getTypes();
|
||||||
|
$map = array_fuse($map);
|
||||||
|
return isset($map[$type]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isUntyped() {
|
||||||
|
return !$this->types;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setBranch($branch) {
|
||||||
|
$this->branch = $branch;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBranch() {
|
||||||
|
return $this->branch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getURIs() {
|
||||||
|
return $this->getHardpoint('uris');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCommitRefs() {
|
||||||
|
return $this->getHardpoint('commitRefs');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
35
src/browse/ref/ArcanistBrowseURIRef.php
Normal file
35
src/browse/ref/ArcanistBrowseURIRef.php
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ArcanistBrowseURIRef
|
||||||
|
extends ArcanistRef {
|
||||||
|
|
||||||
|
private $uri;
|
||||||
|
private $type;
|
||||||
|
|
||||||
|
public function getRefIdentifier() {
|
||||||
|
return pht('Browse URI "%s"', $this->getURI());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function defineHardpoints() {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setURI($uri) {
|
||||||
|
$this->uri = $uri;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getURI() {
|
||||||
|
return $this->uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setType($type) {
|
||||||
|
$this->type = $type;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getType() {
|
||||||
|
return $this->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
259
src/browse/workflow/ArcanistBrowseWorkflow.php
Normal file
259
src/browse/workflow/ArcanistBrowseWorkflow.php
Normal file
|
@ -0,0 +1,259 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Browse files or objects in the Phabricator web interface.
|
||||||
|
*/
|
||||||
|
final class ArcanistBrowseWorkflow extends ArcanistWorkflow {
|
||||||
|
|
||||||
|
public function getWorkflowName() {
|
||||||
|
return 'browse';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCommandSynopses() {
|
||||||
|
return phutil_console_format(<<<EOTEXT
|
||||||
|
**browse** [__options__] __path__ ...
|
||||||
|
**browse** [__options__] __object__ ...
|
||||||
|
EOTEXT
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCommandHelp() {
|
||||||
|
return phutil_console_format(<<<EOTEXT
|
||||||
|
Supports: git, hg, svn
|
||||||
|
Open a file or object (like a task or revision) in your web browser.
|
||||||
|
|
||||||
|
$ arc browse README # Open a file in Diffusion.
|
||||||
|
$ arc browse T123 # View a task.
|
||||||
|
$ arc browse HEAD # View a symbolic commit.
|
||||||
|
|
||||||
|
Set the 'browser' value using 'arc set-config' to select a browser. If
|
||||||
|
no browser is set, the command will try to guess which browser to use.
|
||||||
|
EOTEXT
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getArguments() {
|
||||||
|
return array(
|
||||||
|
'branch' => array(
|
||||||
|
'param' => 'branch_name',
|
||||||
|
'help' => pht(
|
||||||
|
'Default branch name to view on server. Defaults to "%s".',
|
||||||
|
'master'),
|
||||||
|
),
|
||||||
|
'types' => array(
|
||||||
|
'param' => 'types',
|
||||||
|
'aliases' => array('type'),
|
||||||
|
'help' => pht(
|
||||||
|
'Parse arguments with particular types.'),
|
||||||
|
),
|
||||||
|
'force' => array(
|
||||||
|
'help' => pht(
|
||||||
|
'(DEPRECATED) Obsolete, use "--types path" instead.'),
|
||||||
|
),
|
||||||
|
'*' => 'targets',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function desiresWorkingCopy() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function desiresRepositoryAPI() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function run() {
|
||||||
|
$conduit = $this->getConduitEngine();
|
||||||
|
|
||||||
|
$console = PhutilConsole::getConsole();
|
||||||
|
|
||||||
|
$targets = $this->getArgument('targets');
|
||||||
|
$targets = array_fuse($targets);
|
||||||
|
|
||||||
|
if (!$targets) {
|
||||||
|
$refs = array(
|
||||||
|
new ArcanistBrowseRef(),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$refs = array();
|
||||||
|
foreach ($targets as $target) {
|
||||||
|
$refs[] = id(new ArcanistBrowseRef())
|
||||||
|
->setToken($target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$is_force = $this->getArgument('force');
|
||||||
|
if ($is_force) {
|
||||||
|
// TODO: Remove this completely.
|
||||||
|
$this->writeWarn(
|
||||||
|
pht('DEPRECATED'),
|
||||||
|
pht(
|
||||||
|
'Argument "--force" for "arc browse" is deprecated. Use '.
|
||||||
|
'"--type %s" instead.',
|
||||||
|
ArcanistBrowsePathURIHardpointLoader::BROWSETYPE));
|
||||||
|
}
|
||||||
|
|
||||||
|
$types = $this->getArgument('types');
|
||||||
|
if ($types !== null) {
|
||||||
|
$types = preg_split('/[\s,]+/', $types);
|
||||||
|
} else {
|
||||||
|
if ($is_force) {
|
||||||
|
$types = array(ArcanistBrowsePathURIHardpointLoader::BROWSETYPE);
|
||||||
|
} else {
|
||||||
|
$types = array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($refs as $ref) {
|
||||||
|
$ref->setTypes($types);
|
||||||
|
}
|
||||||
|
|
||||||
|
$branch = $this->getArgument('branch');
|
||||||
|
if ($branch) {
|
||||||
|
foreach ($refs as $ref) {
|
||||||
|
$ref->setBranch($branch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$loaders = ArcanistBrowseURIHardpointLoader::getAllBrowseLoaders();
|
||||||
|
foreach ($loaders as $key => $loader) {
|
||||||
|
$loaders[$key] = clone $loader;
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = $this->newRefQuery($refs)
|
||||||
|
->needHardpoints(
|
||||||
|
array(
|
||||||
|
'uris',
|
||||||
|
))
|
||||||
|
->setLoaders($loaders);
|
||||||
|
|
||||||
|
foreach ($loaders as $loader) {
|
||||||
|
$loader->willLoadBrowseURIRefs($refs);
|
||||||
|
}
|
||||||
|
|
||||||
|
$query->execute();
|
||||||
|
|
||||||
|
$zero_hits = array();
|
||||||
|
$open_uris = array();
|
||||||
|
$many_hits = array();
|
||||||
|
foreach ($refs as $ref) {
|
||||||
|
$uris = $ref->getURIs();
|
||||||
|
if (!$uris) {
|
||||||
|
$zero_hits[] = $ref;
|
||||||
|
} else if (count($uris) == 1) {
|
||||||
|
$open_uris[] = $ref;
|
||||||
|
} else {
|
||||||
|
$many_hits[] = $ref;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$pick_map = array();
|
||||||
|
$pick_selection = null;
|
||||||
|
$pick_id = 0;
|
||||||
|
if ($many_hits) {
|
||||||
|
foreach ($many_hits as $ref) {
|
||||||
|
$token = $ref->getToken();
|
||||||
|
if (strlen($token)) {
|
||||||
|
$message = pht('Argument "%s" is ambiguous.', $token);
|
||||||
|
} else {
|
||||||
|
$message = pht('Default behavior is ambiguous.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->writeWarn(pht('AMBIGUOUS'), $message);
|
||||||
|
}
|
||||||
|
|
||||||
|
$is_single_ref = (count($refs) == 1);
|
||||||
|
|
||||||
|
$table = id(new PhutilConsoleTable());
|
||||||
|
|
||||||
|
if ($is_single_ref) {
|
||||||
|
$table->addColumn('pick', array('title' => pht('Pick')));
|
||||||
|
} else {
|
||||||
|
$table->addColumn('argument', array('title' => pht('Argument')));
|
||||||
|
}
|
||||||
|
|
||||||
|
$table
|
||||||
|
->addColumn('type', array('title' => pht('Type')))
|
||||||
|
->addColumn('uri', array('title' => pht('URI')));
|
||||||
|
|
||||||
|
foreach ($many_hits as $ref) {
|
||||||
|
$token_display = $ref->getToken();
|
||||||
|
if (!strlen($token)) {
|
||||||
|
$token_display = pht('<default>');
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($ref->getURIs() as $uri) {
|
||||||
|
++$pick_id;
|
||||||
|
$pick_map[$pick_id] = $uri;
|
||||||
|
|
||||||
|
$row = array(
|
||||||
|
'pick' => $pick_id,
|
||||||
|
'argument' => $token_display,
|
||||||
|
'type' => $uri->getType(),
|
||||||
|
'uri' => $uri->getURI(),
|
||||||
|
);
|
||||||
|
|
||||||
|
$table->addRow($row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$table->draw();
|
||||||
|
|
||||||
|
if ($is_single_ref) {
|
||||||
|
$pick_selection = phutil_console_select(
|
||||||
|
pht('Which URI do you want to open?'),
|
||||||
|
1,
|
||||||
|
$pick_id);
|
||||||
|
$open_uris[] = $ref;
|
||||||
|
} else {
|
||||||
|
$this->writeInfo(
|
||||||
|
pht('CHOOSE'),
|
||||||
|
pht('Use "--types" to select between alternatives.'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If anything failed to resolve, this is also an error.
|
||||||
|
if ($zero_hits) {
|
||||||
|
foreach ($zero_hits as $ref) {
|
||||||
|
$token = $ref->getToken();
|
||||||
|
if ($token === null) {
|
||||||
|
echo tsprintf(
|
||||||
|
"%s\n",
|
||||||
|
pht(
|
||||||
|
'Unable to resolve default browse target.'));
|
||||||
|
} else {
|
||||||
|
echo tsprintf(
|
||||||
|
"%s\n",
|
||||||
|
pht(
|
||||||
|
'Unable to resolve argument "%s".',
|
||||||
|
$ref->getToken()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($loaders as $loader) {
|
||||||
|
$loader->didFailToLoadBrowseURIRefs($refs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$uris = array();
|
||||||
|
foreach ($open_uris as $ref) {
|
||||||
|
$ref_uris = $ref->getURIs();
|
||||||
|
|
||||||
|
if (count($ref_uris) > 1) {
|
||||||
|
foreach ($ref_uris as $uri_key => $uri) {
|
||||||
|
if ($pick_map[$pick_selection] !== $uri) {
|
||||||
|
unset($ref_uris[$uri_key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$ref_uri = head($ref_uris);
|
||||||
|
$uris[] = $ref_uri->getURI();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->openURIsInBrowser($uris);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
155
src/conduit/ArcanistConduitCall.php
Normal file
155
src/conduit/ArcanistConduitCall.php
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ArcanistConduitCall
|
||||||
|
extends Phobject {
|
||||||
|
|
||||||
|
private $key;
|
||||||
|
private $engine;
|
||||||
|
private $method;
|
||||||
|
private $parameters;
|
||||||
|
private $future;
|
||||||
|
|
||||||
|
public function setKey($key) {
|
||||||
|
$this->key = $key;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getKey() {
|
||||||
|
return $this->key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setEngine(ArcanistConduitEngine $engine) {
|
||||||
|
$this->engine = $engine;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEngine() {
|
||||||
|
return $this->engine;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setMethod($method) {
|
||||||
|
$this->method = $method;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMethod() {
|
||||||
|
return $this->method;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setParameters(array $parameters) {
|
||||||
|
$this->parameters = $parameters;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getParameters() {
|
||||||
|
return $this->parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function newFuture() {
|
||||||
|
if ($this->future) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Call has previously generated a future. Create a '.
|
||||||
|
'new call object for each API method invocation.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$method = $this->getMethod();
|
||||||
|
$parameters = $this->getParameters();
|
||||||
|
$future = $this->getEngine()->newFuture($this);
|
||||||
|
$this->future = $future;
|
||||||
|
|
||||||
|
return $this->future;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function resolve() {
|
||||||
|
if (!$this->future) {
|
||||||
|
$this->newFuture();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->getEngine()->resolveFuture($this->getKey());
|
||||||
|
|
||||||
|
return $this->resolveFuture();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function resolveFuture() {
|
||||||
|
$future = $this->future;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$result = $future->resolve();
|
||||||
|
} catch (ConduitClientException $ex) {
|
||||||
|
switch ($ex->getErrorCode()) {
|
||||||
|
case 'ERR-INVALID-SESSION':
|
||||||
|
if (!$this->getEngine()->getConduitToken()) {
|
||||||
|
$this->raiseLoginRequired();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'ERR-INVALID-AUTH':
|
||||||
|
$this->raiseInvalidAuth();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw $ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function raiseLoginRequired() {
|
||||||
|
$conduit_uri = $this->getEngine()->getConduitURI();
|
||||||
|
$conduit_uri = new PhutilURI($conduit_uri);
|
||||||
|
$conduit_uri->setPath('/');
|
||||||
|
|
||||||
|
$conduit_domain = $conduit_uri->getDomain();
|
||||||
|
|
||||||
|
$block = id(new PhutilConsoleBlock())
|
||||||
|
->addParagraph(
|
||||||
|
tsprintf(
|
||||||
|
'**<bg:red> %s </bg>**',
|
||||||
|
pht('LOGIN REQUIRED')))
|
||||||
|
->addParagraph(
|
||||||
|
pht(
|
||||||
|
'You are trying to connect to a server ("%s") that you do not '.
|
||||||
|
'have any stored credentials for, but the command you are '.
|
||||||
|
'running requires authentication.',
|
||||||
|
$conduit_domain))
|
||||||
|
->addParagraph(
|
||||||
|
pht(
|
||||||
|
'To login and save credentials for this server, run this '.
|
||||||
|
'command:'))
|
||||||
|
->addParagraph(
|
||||||
|
tsprintf(
|
||||||
|
" $ arc install-certificate %s\n",
|
||||||
|
$conduit_uri));
|
||||||
|
|
||||||
|
throw new ArcanistUsageException($block->drawConsoleString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private function raiseInvalidAuth() {
|
||||||
|
$conduit_uri = $this->getEngine()->getConduitURI();
|
||||||
|
$conduit_uri = new PhutilURI($conduit_uri);
|
||||||
|
$conduit_uri->setPath('/');
|
||||||
|
|
||||||
|
$conduit_domain = $conduit_uri->getDomain();
|
||||||
|
|
||||||
|
$block = id(new PhutilConsoleBlock())
|
||||||
|
->addParagraph(
|
||||||
|
tsprintf(
|
||||||
|
'**<bg:red> %s </bg>**',
|
||||||
|
pht('INVALID CREDENTIALS')))
|
||||||
|
->addParagraph(
|
||||||
|
pht(
|
||||||
|
'Your stored credentials for this server ("%s") are not valid.',
|
||||||
|
$conduit_domain))
|
||||||
|
->addParagraph(
|
||||||
|
pht(
|
||||||
|
'To login and save valid credentials for this server, run this '.
|
||||||
|
'command:'))
|
||||||
|
->addParagraph(
|
||||||
|
tsprintf(
|
||||||
|
" $ arc install-certificate %s\n",
|
||||||
|
$conduit_uri));
|
||||||
|
|
||||||
|
throw new ArcanistUsageException($block->drawConsoleString());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
166
src/conduit/ArcanistConduitEngine.php
Normal file
166
src/conduit/ArcanistConduitEngine.php
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ArcanistConduitEngine
|
||||||
|
extends Phobject {
|
||||||
|
|
||||||
|
private $conduitURI;
|
||||||
|
private $conduitToken;
|
||||||
|
|
||||||
|
private $conduitTimeout;
|
||||||
|
private $basicAuthUser;
|
||||||
|
private $basicAuthPass;
|
||||||
|
|
||||||
|
private $client;
|
||||||
|
private $callKey = 0;
|
||||||
|
private $activeFutures = array();
|
||||||
|
private $resolvedFutures = array();
|
||||||
|
|
||||||
|
public function isCallable() {
|
||||||
|
return ($this->conduitURI !== null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setConduitURI($conduit_uri) {
|
||||||
|
$this->conduitURI = $conduit_uri;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getConduitURI() {
|
||||||
|
return $this->conduitURI;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setConduitToken($conduit_token) {
|
||||||
|
$this->conduitToken = $conduit_token;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getConduitToken() {
|
||||||
|
return $this->conduitToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setConduitTimeout($conduit_timeout) {
|
||||||
|
$this->conduitTimeout = $conduit_timeout;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getConduitTimeout() {
|
||||||
|
return $this->conduitTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setBasicAuthUser($basic_auth_user) {
|
||||||
|
$this->basicAuthUser = $basic_auth_user;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBasicAuthUser() {
|
||||||
|
return $this->basicAuthUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setBasicAuthPass($basic_auth_pass) {
|
||||||
|
$this->basicAuthPass = $basic_auth_pass;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBasicAuthPass() {
|
||||||
|
return $this->basicAuthPass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newCall($method, array $parameters) {
|
||||||
|
if ($this->conduitURI == null) {
|
||||||
|
$this->raiseURIException();
|
||||||
|
}
|
||||||
|
|
||||||
|
$next_key = ++$this->callKey;
|
||||||
|
|
||||||
|
return id(new ArcanistConduitCall())
|
||||||
|
->setKey($next_key)
|
||||||
|
->setEngine($this)
|
||||||
|
->setMethod($method)
|
||||||
|
->setParameters($parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function resolveCall($method, array $parameters) {
|
||||||
|
return $this->newCall($method, $parameters)->resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newFuture(ArcanistConduitCall $call) {
|
||||||
|
$method = $call->getMethod();
|
||||||
|
$parameters = $call->getParameters();
|
||||||
|
|
||||||
|
$future = $this->getClient()->callMethod($method, $parameters);
|
||||||
|
$this->activeFutures[$call->getKey()] = $future;
|
||||||
|
return $future;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getClient() {
|
||||||
|
if (!$this->client) {
|
||||||
|
$conduit_uri = $this->getConduitURI();
|
||||||
|
|
||||||
|
$client = new ConduitClient($conduit_uri);
|
||||||
|
|
||||||
|
$timeout = $this->getConduitTimeout();
|
||||||
|
if ($timeout) {
|
||||||
|
$client->setTimeout($timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
$basic_user = $this->getBasicAuthUser();
|
||||||
|
$basic_pass = $this->getBasicAuthPass();
|
||||||
|
if ($basic_user !== null || $basic_pass !== null) {
|
||||||
|
$client->setBasicAuthCredentials($basic_user, $basic_pass);
|
||||||
|
}
|
||||||
|
|
||||||
|
$token = $this->getConduitToken();
|
||||||
|
if ($token) {
|
||||||
|
$client->setConduitToken($this->getConduitToken());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $client;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function resolveFuture($key) {
|
||||||
|
if (isset($this->resolvedFutures[$key])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($this->activeFutures[$key])) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'No future with key "%s" is present in pool.',
|
||||||
|
$key));
|
||||||
|
}
|
||||||
|
|
||||||
|
$iterator = new FutureIterator($this->activeFutures);
|
||||||
|
foreach ($iterator as $future_key => $future) {
|
||||||
|
$this->resolvedFutures[$future_key] = $future;
|
||||||
|
unset($this->activeFutures[$future_key]);
|
||||||
|
if ($future_key == $key) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function raiseURIException() {
|
||||||
|
$list = id(new PhutilConsoleList())
|
||||||
|
->addItem(
|
||||||
|
pht(
|
||||||
|
'Run in a working copy with "phabricator.uri" set in ".arcconfig".'))
|
||||||
|
->addItem(
|
||||||
|
pht(
|
||||||
|
'Set a default URI with `arc set-config default <uri>`.'))
|
||||||
|
->addItem(
|
||||||
|
pht(
|
||||||
|
'Specify a URI explicitly with `--conduit-uri=<uri>`.'));
|
||||||
|
|
||||||
|
$block = id(new PhutilConsoleBlock())
|
||||||
|
->addParagraph(
|
||||||
|
pht(
|
||||||
|
'This command needs to communicate with Phabricator, but no '.
|
||||||
|
'Phabricator URI is configured.'))
|
||||||
|
->addList($list);
|
||||||
|
|
||||||
|
throw new ArcanistUsageException($block->drawConsoleString());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
48
src/configuration/ArcanistSetting.php
Normal file
48
src/configuration/ArcanistSetting.php
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class ArcanistSetting
|
||||||
|
extends Phobject {
|
||||||
|
|
||||||
|
final public function getSettingKey() {
|
||||||
|
return $this->getPhobjectClassConstant('SETTINGKEY', 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAliases() {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract public function getHelp();
|
||||||
|
abstract public function getType();
|
||||||
|
|
||||||
|
public function getExample() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function getLegacyDictionary() {
|
||||||
|
$result = array(
|
||||||
|
'type' => $this->getType(),
|
||||||
|
'help' => $this->getHelp(),
|
||||||
|
);
|
||||||
|
|
||||||
|
$example = $this->getExample();
|
||||||
|
if ($example !== null) {
|
||||||
|
$result['example'] = $example;
|
||||||
|
}
|
||||||
|
|
||||||
|
$aliases = $this->getAliases();
|
||||||
|
if ($aliases) {
|
||||||
|
$result['legacy'] = head($aliases);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public static function getAllSettings() {
|
||||||
|
return id(new PhutilClassMapQuery())
|
||||||
|
->setAncestorClass(__CLASS__)
|
||||||
|
->setUniqueMethod('getSettingKey')
|
||||||
|
->setSortMethod('getSettingKey')
|
||||||
|
->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,7 +3,7 @@
|
||||||
final class ArcanistSettings extends Phobject {
|
final class ArcanistSettings extends Phobject {
|
||||||
|
|
||||||
private function getOptions() {
|
private function getOptions() {
|
||||||
return array(
|
$legacy_builtins = array(
|
||||||
'default' => array(
|
'default' => array(
|
||||||
'type' => 'string',
|
'type' => 'string',
|
||||||
'help' => pht(
|
'help' => pht(
|
||||||
|
@ -80,19 +80,6 @@ final class ArcanistSettings extends Phobject {
|
||||||
'arc land'),
|
'arc land'),
|
||||||
'example' => '"develop"',
|
'example' => '"develop"',
|
||||||
),
|
),
|
||||||
'arc.lint.cache' => array(
|
|
||||||
'type' => 'bool',
|
|
||||||
'help' => pht(
|
|
||||||
'Enable the lint cache by default. When enabled, `%s` attempts to '.
|
|
||||||
'use cached results if possible. Currently, the cache is not always '.
|
|
||||||
'invalidated correctly and may cause `%s` to report incorrect '.
|
|
||||||
'results, particularly while developing linters. This is probably '.
|
|
||||||
'worth enabling only if your linters are very slow.',
|
|
||||||
'arc lint',
|
|
||||||
'arc lint'),
|
|
||||||
'default' => false,
|
|
||||||
'example' => 'false',
|
|
||||||
),
|
|
||||||
'history.immutable' => array(
|
'history.immutable' => array(
|
||||||
'type' => 'bool',
|
'type' => 'bool',
|
||||||
'legacy' => 'immutable_history',
|
'legacy' => 'immutable_history',
|
||||||
|
@ -168,6 +155,16 @@ final class ArcanistSettings extends Phobject {
|
||||||
'Configured command aliases. Use "arc alias" to define aliases.'),
|
'Configured command aliases. Use "arc alias" to define aliases.'),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$settings = ArcanistSetting::getAllSettings();
|
||||||
|
foreach ($settings as $key => $setting) {
|
||||||
|
$settings[$key] = $setting->getLegacyDictionary();
|
||||||
|
}
|
||||||
|
|
||||||
|
$results = $settings + $legacy_builtins;
|
||||||
|
ksort($results);
|
||||||
|
|
||||||
|
return $results;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getOption($key) {
|
private function getOption($key) {
|
||||||
|
|
59
src/loader/ArcanistCommitUpstreamHardpointLoader.php
Normal file
59
src/loader/ArcanistCommitUpstreamHardpointLoader.php
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ArcanistCommitUpstreamHardpointLoader
|
||||||
|
extends ArcanistHardpointLoader {
|
||||||
|
|
||||||
|
const LOADERKEY = 'commit.conduit';
|
||||||
|
|
||||||
|
public function canLoadRepositoryAPI(ArcanistRepositoryAPI $api) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canLoadRef(ArcanistRef $ref) {
|
||||||
|
return ($ref instanceof ArcanistCommitRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canLoadHardpoint(ArcanistRef $ref, $hardpoint) {
|
||||||
|
return ($hardpoint == 'upstream');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function loadHardpoints(array $refs, $hardpoint) {
|
||||||
|
$query = $this->getQuery();
|
||||||
|
|
||||||
|
$repository_ref = $query->getRepositoryRef();
|
||||||
|
if (!$repository_ref) {
|
||||||
|
return array_fill_keys(array_keys($refs), null);
|
||||||
|
}
|
||||||
|
$repository_phid = $repository_ref->getPHID();
|
||||||
|
|
||||||
|
$commit_map = array();
|
||||||
|
foreach ($refs as $key => $ref) {
|
||||||
|
$hash = $ref->getCommitHash();
|
||||||
|
$commit_map[$hash][] = $key;
|
||||||
|
}
|
||||||
|
|
||||||
|
$commit_info = $this->resolveCall(
|
||||||
|
'diffusion.querycommits',
|
||||||
|
array(
|
||||||
|
'repositoryPHID' => $repository_phid,
|
||||||
|
'names' => array_keys($commit_map),
|
||||||
|
));
|
||||||
|
|
||||||
|
$results = array();
|
||||||
|
foreach ($commit_map as $hash => $keys) {
|
||||||
|
$commit_phid = idx($commit_info['identifierMap'], $hash);
|
||||||
|
if ($commit_phid) {
|
||||||
|
$commit_data = idx($commit_info['data'], $commit_phid);
|
||||||
|
} else {
|
||||||
|
$commit_data = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($keys as $key) {
|
||||||
|
$results[$key] = $commit_data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
41
src/loader/ArcanistGitCommitMessageHardpointLoader.php
Normal file
41
src/loader/ArcanistGitCommitMessageHardpointLoader.php
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ArcanistGitCommitMessageHardpointLoader
|
||||||
|
extends ArcanistGitHardpointLoader {
|
||||||
|
|
||||||
|
const LOADERKEY = 'git.commit.message';
|
||||||
|
|
||||||
|
public function canLoadRef(ArcanistRef $ref) {
|
||||||
|
return ($ref instanceof ArcanistCommitRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canLoadHardpoint(ArcanistRef $ref, $hardpoint) {
|
||||||
|
return ($hardpoint == 'message');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function loadHardpoints(array $refs, $hardpoint) {
|
||||||
|
$api = $this->getQuery()->getRepositoryAPI();
|
||||||
|
|
||||||
|
|
||||||
|
$futures = array();
|
||||||
|
foreach ($refs as $ref_key => $ref) {
|
||||||
|
$hash = $ref->getCommitHash();
|
||||||
|
|
||||||
|
$futures[$ref_key] = $api->execFutureLocal(
|
||||||
|
'log -n1 --format=%C %s --',
|
||||||
|
'%s%n%n%b',
|
||||||
|
$hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
$iterator = $this->newFutureIterator($futures);
|
||||||
|
|
||||||
|
$results = array();
|
||||||
|
foreach ($iterator as $ref_key => $future) {
|
||||||
|
list($stdout) = $future->resolvex();
|
||||||
|
$results[$ref_key] = $stdout;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
10
src/loader/ArcanistGitHardpointLoader.php
Normal file
10
src/loader/ArcanistGitHardpointLoader.php
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class ArcanistGitHardpointLoader
|
||||||
|
extends ArcanistHardpointLoader {
|
||||||
|
|
||||||
|
public function canLoadRepositoryAPI(ArcanistRepositoryAPI $api) {
|
||||||
|
return ($api instanceof ArcanistGitAPI);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
82
src/loader/ArcanistGitRevisionHardpointLoader.php
Normal file
82
src/loader/ArcanistGitRevisionHardpointLoader.php
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ArcanistGitRevisionHardpointLoader
|
||||||
|
extends ArcanistGitHardpointLoader {
|
||||||
|
|
||||||
|
const LOADERKEY = 'git.revision';
|
||||||
|
|
||||||
|
public function canLoadRef(ArcanistRef $ref) {
|
||||||
|
return ($ref instanceof ArcanistWorkingCopyStateRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canLoadHardpoint(ArcanistRef $ref, $hardpoint) {
|
||||||
|
return ($hardpoint == 'revisionRefs');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function loadHardpoints(array $refs, $hardpoint) {
|
||||||
|
$this->newQuery($refs)
|
||||||
|
->needHardpoints(
|
||||||
|
array(
|
||||||
|
'commitRef',
|
||||||
|
))
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$hashes = array();
|
||||||
|
$map = array();
|
||||||
|
foreach ($refs as $ref_key => $ref) {
|
||||||
|
$commit = $ref->getCommitRef();
|
||||||
|
|
||||||
|
$commit_hashes = array();
|
||||||
|
|
||||||
|
$commit_hashes[] = array(
|
||||||
|
'gtcm',
|
||||||
|
$commit->getCommitHash(),
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($commit->getTreeHash()) {
|
||||||
|
$commit_hashes[] = array(
|
||||||
|
'gttr',
|
||||||
|
$commit->getTreeHash(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($commit_hashes as $hash) {
|
||||||
|
$hashes[] = $hash;
|
||||||
|
$hash_key = $this->getHashKey($hash);
|
||||||
|
$map[$hash_key][$ref_key] = $ref;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$results = array();
|
||||||
|
if ($hashes) {
|
||||||
|
$revisions = $this->resolveCall(
|
||||||
|
'differential.query',
|
||||||
|
array(
|
||||||
|
'commitHashes' => $hashes,
|
||||||
|
));
|
||||||
|
|
||||||
|
foreach ($revisions as $dict) {
|
||||||
|
$revision_hashes = idx($dict, 'hashes');
|
||||||
|
if (!$revision_hashes) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$revision_ref = ArcanistRevisionRef::newFromConduit($dict);
|
||||||
|
foreach ($revision_hashes as $revision_hash) {
|
||||||
|
$hash_key = $this->getHashKey($revision_hash);
|
||||||
|
$state_refs = idx($map, $hash_key, array());
|
||||||
|
foreach ($state_refs as $ref_key => $state_ref) {
|
||||||
|
$results[$ref_key][] = $revision_ref;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getHashKey(array $hash) {
|
||||||
|
return $hash[0].':'.$hash[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
76
src/loader/ArcanistHardpointLoader.php
Normal file
76
src/loader/ArcanistHardpointLoader.php
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class ArcanistHardpointLoader
|
||||||
|
extends Phobject {
|
||||||
|
|
||||||
|
private $query;
|
||||||
|
private $conduitEngine;
|
||||||
|
|
||||||
|
abstract public function canLoadRepositoryAPI(ArcanistRepositoryAPI $api);
|
||||||
|
abstract public function canLoadRef(ArcanistRef $ref);
|
||||||
|
abstract public function canLoadHardpoint(ArcanistRef $ref, $hardpoint);
|
||||||
|
abstract public function loadHardpoints(array $refs, $hardpoint);
|
||||||
|
|
||||||
|
final public function setQuery(ArcanistRefQuery $query) {
|
||||||
|
$this->query = $query;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function getQuery() {
|
||||||
|
return $this->query;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function getConduitEngine() {
|
||||||
|
return $this->getQuery()->getConduitEngine();
|
||||||
|
}
|
||||||
|
|
||||||
|
final protected function newQuery(array $refs) {
|
||||||
|
$result = id(new ArcanistRefQuery())
|
||||||
|
->setConduitEngine($this->getQuery()->getConduitEngine())
|
||||||
|
->setRefs($refs);
|
||||||
|
|
||||||
|
$query = $this->getQuery();
|
||||||
|
|
||||||
|
$repository_api = $query->getRepositoryAPI();
|
||||||
|
if ($repository_api) {
|
||||||
|
$result->setRepositoryAPI($repository_api);
|
||||||
|
}
|
||||||
|
|
||||||
|
$repository_ref = $query->getRepositoryRef();
|
||||||
|
if ($repository_ref) {
|
||||||
|
$result->setRepositoryRef($repository_ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
$working_ref = $query->getWorkingCopyRef();
|
||||||
|
if ($working_ref) {
|
||||||
|
$result->setWorkingCopyRef($working_ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function getLoaderKey() {
|
||||||
|
return $this->getPhobjectClassConstant('LOADERKEY', 64);
|
||||||
|
}
|
||||||
|
|
||||||
|
final public static function getAllLoaders() {
|
||||||
|
return id(new PhutilClassMapQuery())
|
||||||
|
->setAncestorClass(__CLASS__)
|
||||||
|
->setUniqueMethod('getLoaderKey')
|
||||||
|
->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function resolveCall($method, array $parameters) {
|
||||||
|
return $this->newCall($method, $parameters)->resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function newCall($method, array $parameters) {
|
||||||
|
return $this->getConduitEngine()->newCall($method, $parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
final protected function newFutureIterator(array $futures) {
|
||||||
|
return id(new FutureIterator($futures))
|
||||||
|
->limit(16);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
49
src/loader/ArcanistMercurialBranchCommitHardpointLoader.php
Normal file
49
src/loader/ArcanistMercurialBranchCommitHardpointLoader.php
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ArcanistMercurialBranchCommitHardpointLoader
|
||||||
|
extends ArcanistMercurialHardpointLoader {
|
||||||
|
|
||||||
|
const LOADERKEY = 'hg.branch.commit';
|
||||||
|
|
||||||
|
public function canLoadRef(ArcanistRef $ref) {
|
||||||
|
return ($ref instanceof ArcanistBranchRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canLoadHardpoint(ArcanistRef $ref, $hardpoint) {
|
||||||
|
return ($hardpoint == 'commitRef');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function loadHardpoints(array $refs, $hardpoint) {
|
||||||
|
$api = $this->getQuery()->getRepositoryAPI();
|
||||||
|
|
||||||
|
$futures = array();
|
||||||
|
foreach ($refs as $ref_key => $branch) {
|
||||||
|
$branch_name = $branch->getBranchName();
|
||||||
|
|
||||||
|
$futures[$ref_key] = $api->execFutureLocal(
|
||||||
|
'log -l 1 --template %s -r %s',
|
||||||
|
"{node}\1{date|hgdate}\1{p1node}\1{desc|firstline}\1{desc}",
|
||||||
|
hgsprintf('%s', $branch_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
$results = array();
|
||||||
|
|
||||||
|
$iterator = $this->newFutureIterator($futures);
|
||||||
|
foreach ($iterator as $ref_key => $future) {
|
||||||
|
list($info) = $future->resolvex();
|
||||||
|
|
||||||
|
$fields = explode("\1", trim($info), 5);
|
||||||
|
list($hash, $epoch, $parent, $desc, $text) = $fields;
|
||||||
|
|
||||||
|
$commit_ref = $api->newCommitRef()
|
||||||
|
->setCommitHash($hash)
|
||||||
|
->setCommitEpoch((int)$epoch)
|
||||||
|
->attachMessage($text);
|
||||||
|
|
||||||
|
$results[$ref_key] = $commit_ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
10
src/loader/ArcanistMercurialHardpointLoader.php
Normal file
10
src/loader/ArcanistMercurialHardpointLoader.php
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class ArcanistMercurialHardpointLoader
|
||||||
|
extends ArcanistHardpointLoader {
|
||||||
|
|
||||||
|
public function canLoadRepositoryAPI(ArcanistRepositoryAPI $api) {
|
||||||
|
return ($api instanceof ArcanistMercurialAPI);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ArcanistMercurialWorkingCopyCommitHardpointLoader
|
||||||
|
extends ArcanistMercurialHardpointLoader {
|
||||||
|
|
||||||
|
const LOADERKEY = 'hg.state.commit';
|
||||||
|
|
||||||
|
public function canLoadRef(ArcanistRef $ref) {
|
||||||
|
return ($ref instanceof ArcanistWorkingCopyStateRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canLoadHardpoint(ArcanistRef $ref, $hardpoint) {
|
||||||
|
return ($hardpoint == 'commitRef');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function loadHardpoints(array $refs, $hardpoint) {
|
||||||
|
$branch_refs = array();
|
||||||
|
foreach ($refs as $ref_key => $ref) {
|
||||||
|
if ($ref->hasAttachedHardpoint('branchRef')) {
|
||||||
|
$branch_refs[$ref_key] = $ref->getBranchRef();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($branch_refs) {
|
||||||
|
$this->newQuery($branch_refs)
|
||||||
|
->needHardpoints(
|
||||||
|
array(
|
||||||
|
'commitRef',
|
||||||
|
))
|
||||||
|
->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
return mpull($branch_refs, 'getCommitRef');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
82
src/loader/ArcanistMessageRevisionHardpointLoader.php
Normal file
82
src/loader/ArcanistMessageRevisionHardpointLoader.php
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ArcanistMessageRevisionHardpointLoader
|
||||||
|
extends ArcanistHardpointLoader {
|
||||||
|
|
||||||
|
const LOADERKEY = 'message.revision';
|
||||||
|
|
||||||
|
public function canLoadRepositoryAPI(ArcanistRepositoryAPI $api) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canLoadRef(ArcanistRef $ref) {
|
||||||
|
return ($ref instanceof ArcanistWorkingCopyStateRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canLoadHardpoint(ArcanistRef $ref, $hardpoint) {
|
||||||
|
return ($hardpoint == 'revisionRefs');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function loadHardpoints(array $refs, $hardpoint) {
|
||||||
|
$this->newQuery($refs)
|
||||||
|
->needHardpoints(
|
||||||
|
array(
|
||||||
|
'commitRef',
|
||||||
|
))
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$commit_refs = array();
|
||||||
|
foreach ($refs as $ref) {
|
||||||
|
$commit_refs[] = $ref->getCommitRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->newQuery($commit_refs)
|
||||||
|
->needHardpoints(
|
||||||
|
array(
|
||||||
|
'message',
|
||||||
|
))
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$map = array();
|
||||||
|
foreach ($refs as $ref_key => $ref) {
|
||||||
|
$commit_ref = $ref->getCommitRef();
|
||||||
|
$corpus = $commit_ref->getMessage();
|
||||||
|
|
||||||
|
$id = null;
|
||||||
|
try {
|
||||||
|
$message = ArcanistDifferentialCommitMessage::newFromRawCorpus($corpus);
|
||||||
|
$id = $message->getRevisionID();
|
||||||
|
} catch (ArcanistUsageException $ex) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$map[$id][$ref_key] = $ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
$results = array();
|
||||||
|
if ($map) {
|
||||||
|
$revisions = $this->resolveCall(
|
||||||
|
'differential.query',
|
||||||
|
array(
|
||||||
|
'ids' => array_keys($map),
|
||||||
|
));
|
||||||
|
|
||||||
|
foreach ($revisions as $dict) {
|
||||||
|
$revision_ref = ArcanistRevisionRef::newFromConduit($dict);
|
||||||
|
$id = $dict['id'];
|
||||||
|
|
||||||
|
$state_refs = idx($map, $id, array());
|
||||||
|
foreach ($state_refs as $ref_key => $state_ref) {
|
||||||
|
$results[$ref_key][] = $revision_ref;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
57
src/ref/ArcanistBranchRef.php
Normal file
57
src/ref/ArcanistBranchRef.php
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ArcanistBranchRef
|
||||||
|
extends ArcanistRef {
|
||||||
|
|
||||||
|
private $branchName;
|
||||||
|
private $refName;
|
||||||
|
private $isCurrentBranch;
|
||||||
|
|
||||||
|
public function getRefIdentifier() {
|
||||||
|
return pht('Branch %s', $this->getBranchName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function defineHardpoints() {
|
||||||
|
return array(
|
||||||
|
'commitRef' => array(
|
||||||
|
'type' => 'ArcanistCommitRef',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setBranchName($branch_name) {
|
||||||
|
$this->branchName = $branch_name;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBranchName() {
|
||||||
|
return $this->branchName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setRefName($ref_name) {
|
||||||
|
$this->refName = $ref_name;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRefName() {
|
||||||
|
return $this->refName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setIsCurrentBranch($is_current_branch) {
|
||||||
|
$this->isCurrentBranch = $is_current_branch;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIsCurrentBranch() {
|
||||||
|
return $this->isCurrentBranch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function attachCommitRef(ArcanistCommitRef $ref) {
|
||||||
|
return $this->attachHardpoint('commitRef', $ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCommitRef() {
|
||||||
|
return $this->getHardpoint('commitRef');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
94
src/ref/ArcanistCommitRef.php
Normal file
94
src/ref/ArcanistCommitRef.php
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ArcanistCommitRef
|
||||||
|
extends ArcanistRef {
|
||||||
|
|
||||||
|
private $commitHash;
|
||||||
|
private $treeHash;
|
||||||
|
private $commitEpoch;
|
||||||
|
private $authorEpoch;
|
||||||
|
private $upstream;
|
||||||
|
|
||||||
|
public function getRefIdentifier() {
|
||||||
|
return pht('Commit %s', $this->getCommitHash());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function defineHardpoints() {
|
||||||
|
return array(
|
||||||
|
'message' => array(
|
||||||
|
'type' => 'string',
|
||||||
|
),
|
||||||
|
'upstream' => array(
|
||||||
|
'type' => 'wild',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setCommitHash($commit_hash) {
|
||||||
|
$this->commitHash = $commit_hash;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCommitHash() {
|
||||||
|
return $this->commitHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setTreeHash($tree_hash) {
|
||||||
|
$this->treeHash = $tree_hash;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTreeHash() {
|
||||||
|
return $this->treeHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setCommitEpoch($commit_epoch) {
|
||||||
|
$this->commitEpoch = $commit_epoch;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCommitEpoch() {
|
||||||
|
return $this->commitEpoch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setAuthorEpoch($author_epoch) {
|
||||||
|
$this->authorEpoch = $author_epoch;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAuthorEpoch() {
|
||||||
|
return $this->authorEpoch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSummary() {
|
||||||
|
$message = $this->getMessage();
|
||||||
|
|
||||||
|
$message = trim($message);
|
||||||
|
$lines = phutil_split_lines($message, false);
|
||||||
|
|
||||||
|
return head($lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function attachMessage($message) {
|
||||||
|
return $this->attachHardpoint('message', $message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMessage() {
|
||||||
|
return $this->getHardpoint('message');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getURI() {
|
||||||
|
return $this->getUpstreamProperty('uri');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getUpstreamProperty($key, $default = null) {
|
||||||
|
$upstream = $this->getHardpoint('upstream');
|
||||||
|
|
||||||
|
if (!$upstream) {
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
return idx($upstream, $key, $default);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
106
src/ref/ArcanistRef.php
Normal file
106
src/ref/ArcanistRef.php
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class ArcanistRef
|
||||||
|
extends Phobject {
|
||||||
|
|
||||||
|
private $hardpoints = array();
|
||||||
|
|
||||||
|
abstract public function getRefIdentifier();
|
||||||
|
abstract public function defineHardpoints();
|
||||||
|
|
||||||
|
final public function hasHardpoint($hardpoint) {
|
||||||
|
$map = $this->getHardpointMap();
|
||||||
|
return isset($map[$hardpoint]);
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function hasAttachedHardpoint($hardpoint) {
|
||||||
|
if (array_key_exists($hardpoint, $this->hardpoints)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->canReadHardpoint($hardpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function attachHardpoint($hardpoint, $value) {
|
||||||
|
if (!$this->hasHardpoint($hardpoint)) {
|
||||||
|
throw new Exception(pht('No hardpoint "%s".', $hardpoint));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->hardpoints[$hardpoint] = $value;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function appendHardpoint($hardpoint, array $value) {
|
||||||
|
if (!$this->isVectorHardpoint($hardpoint)) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Hardpoint "%s" is not a vector hardpoint.',
|
||||||
|
$hardpoint));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($this->hardpoints[$hardpoint])) {
|
||||||
|
$this->hardpoints[$hardpoint] = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->hardpoints[$hardpoint] = $this->mergeHardpoint(
|
||||||
|
$hardpoint,
|
||||||
|
$this->hardpoints[$hardpoint],
|
||||||
|
$value);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function mergeHardpoint($hardpoint, array $src, array $new) {
|
||||||
|
foreach ($new as $value) {
|
||||||
|
$src[] = $value;
|
||||||
|
}
|
||||||
|
return $src;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function isVectorHardpoint($hardpoint) {
|
||||||
|
if (!$this->hasHardpoint($hardpoint)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$map = $this->getHardpointMap();
|
||||||
|
$spec = idx($map, $hardpoint, array());
|
||||||
|
|
||||||
|
return (idx($spec, 'vector') === true);
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function getHardpoint($hardpoint) {
|
||||||
|
if (!$this->hasAttachedHardpoint($hardpoint)) {
|
||||||
|
if (!$this->hasHardpoint($hardpoint)) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Ref does not have hardpoint "%s"!',
|
||||||
|
$hardpoint));
|
||||||
|
} else {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Hardpoint "%s" is not attached!',
|
||||||
|
$hardpoint));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array_key_exists($hardpoint, $this->hardpoints)) {
|
||||||
|
return $this->hardpoints[$hardpoint];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->readHardpoint($hardpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getHardpointMap() {
|
||||||
|
return $this->defineHardpoints();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function canReadHardpoint($hardpoint) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function readHardpoint($hardpoint) {
|
||||||
|
throw new Exception(pht('Can not read hardpoint "%s".', $hardpoint));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
188
src/ref/ArcanistRefQuery.php
Normal file
188
src/ref/ArcanistRefQuery.php
Normal file
|
@ -0,0 +1,188 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ArcanistRefQuery extends Phobject {
|
||||||
|
|
||||||
|
private $repositoryAPI;
|
||||||
|
private $conduitEngine;
|
||||||
|
private $repositoryRef;
|
||||||
|
private $workingCopyRef;
|
||||||
|
|
||||||
|
private $refs;
|
||||||
|
private $hardpoints;
|
||||||
|
private $loaders;
|
||||||
|
|
||||||
|
public function setRefs(array $refs) {
|
||||||
|
assert_instances_of($refs, 'ArcanistRef');
|
||||||
|
$this->refs = $refs;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRefs() {
|
||||||
|
return $this->refs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setRepositoryAPI(ArcanistRepositoryAPI $repository_api) {
|
||||||
|
$this->repositoryAPI = $repository_api;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRepositoryAPI() {
|
||||||
|
return $this->repositoryAPI;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setRepositoryRef(ArcanistRepositoryRef $repository_ref) {
|
||||||
|
$this->repositoryRef = $repository_ref;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
public function getRepositoryRef() {
|
||||||
|
return $this->repositoryRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setConduitEngine(ArcanistConduitEngine $conduit_engine) {
|
||||||
|
$this->conduitEngine = $conduit_engine;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getConduitEngine() {
|
||||||
|
return $this->conduitEngine;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setWorkingCopyRef(ArcanistWorkingCopyStateRef $working_ref) {
|
||||||
|
$this->workingCopyRef = $working_ref;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getWorkingCopyRef() {
|
||||||
|
return $this->workingCopyRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function needHardpoints(array $hardpoints) {
|
||||||
|
$this->hardpoints = $hardpoints;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setLoaders(array $loaders) {
|
||||||
|
assert_instances_of($loaders, 'ArcanistHardpointLoader');
|
||||||
|
|
||||||
|
foreach ($loaders as $key => $loader) {
|
||||||
|
$loader->setQuery($this);
|
||||||
|
}
|
||||||
|
$this->loaders = $loaders;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute() {
|
||||||
|
$refs = $this->getRefs();
|
||||||
|
|
||||||
|
if ($this->refs === null) {
|
||||||
|
throw new PhutilInvalidStateException('setRefs');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->hardpoints === null) {
|
||||||
|
throw new PhutilInvalidStateException('needHardpoints');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->loaders == null) {
|
||||||
|
$all_loaders = ArcanistHardpointLoader::getAllLoaders();
|
||||||
|
foreach ($all_loaders as $key => $loader) {
|
||||||
|
$all_loaders[$key] = clone $loader;
|
||||||
|
}
|
||||||
|
$this->setLoaders($all_loaders);
|
||||||
|
}
|
||||||
|
|
||||||
|
$all_loaders = $this->loaders;
|
||||||
|
|
||||||
|
$api = $this->getRepositoryAPI();
|
||||||
|
$loaders = array();
|
||||||
|
foreach ($all_loaders as $loader_key => $loader) {
|
||||||
|
if ($api) {
|
||||||
|
if (!$loader->canLoadRepositoryAPI($api)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$loaders[$loader_key] = id(clone $loader)
|
||||||
|
->setQuery($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->hardpoints as $hardpoint) {
|
||||||
|
$load = array();
|
||||||
|
$need = array();
|
||||||
|
$has_hardpoint = false;
|
||||||
|
foreach ($refs as $ref_key => $ref) {
|
||||||
|
if (!$ref->hasHardpoint($hardpoint)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$has_hardpoint = true;
|
||||||
|
|
||||||
|
if ($ref->hasAttachedHardpoint($hardpoint)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($loaders as $loader_key => $loader) {
|
||||||
|
if (!$loader->canLoadRef($ref)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$loader->canLoadHardpoint($ref, $hardpoint)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$load[$loader_key][$ref_key] = $ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
$need[$ref_key] = $ref_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($refs && !$has_hardpoint) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'No ref in query has hardpoint "%s".',
|
||||||
|
$hardpoint));
|
||||||
|
}
|
||||||
|
|
||||||
|
$vectors = array();
|
||||||
|
foreach ($need as $ref_key) {
|
||||||
|
$ref = $refs[$ref_key];
|
||||||
|
if ($ref->isVectorHardpoint($hardpoint)) {
|
||||||
|
$vectors[$ref_key] = $ref_key;
|
||||||
|
$ref->attachHardpoint($hardpoint, array());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($load as $loader_key => $loader_refs) {
|
||||||
|
$loader_refs = array_select_keys($loader_refs, $need);
|
||||||
|
|
||||||
|
$loader = $loaders[$loader_key];
|
||||||
|
$data = $loader->loadHardpoints($loader_refs, $hardpoint);
|
||||||
|
|
||||||
|
foreach ($data as $ref_key => $value) {
|
||||||
|
$ref = $refs[$ref_key];
|
||||||
|
if (isset($vectors[$ref_key])) {
|
||||||
|
$ref->appendHardpoint($hardpoint, $value);
|
||||||
|
} else {
|
||||||
|
unset($need[$ref_key]);
|
||||||
|
$ref->attachHardpoint($hardpoint, $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($vectors as $ref_key) {
|
||||||
|
unset($need[$ref_key]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($need) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Nothing could attach data to hardpoint "%s" for ref "%s".',
|
||||||
|
$hardpoint,
|
||||||
|
$refs[head($need)]->getRefIdentifier()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $refs;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
79
src/ref/ArcanistRepositoryRef.php
Normal file
79
src/ref/ArcanistRepositoryRef.php
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ArcanistRepositoryRef
|
||||||
|
extends ArcanistRef {
|
||||||
|
|
||||||
|
private $phid;
|
||||||
|
private $browseURI;
|
||||||
|
|
||||||
|
public function getRefIdentifier() {
|
||||||
|
return pht('Remote Repository');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function defineHardpoints() {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setPHID($phid) {
|
||||||
|
$this->phid = $phid;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPHID() {
|
||||||
|
return $this->phid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setBrowseURI($browse_uri) {
|
||||||
|
$this->browseURI = $browse_uri;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newBrowseURI(array $params) {
|
||||||
|
PhutilTypeSpec::checkMap(
|
||||||
|
$params,
|
||||||
|
array(
|
||||||
|
'path' => 'optional string|null',
|
||||||
|
'branch' => 'optional string|null',
|
||||||
|
'lines' => 'optional string|null',
|
||||||
|
));
|
||||||
|
|
||||||
|
foreach ($params as $key => $value) {
|
||||||
|
if (!strlen($value)) {
|
||||||
|
unset($params[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$defaults = array(
|
||||||
|
'path' => '/',
|
||||||
|
'branch' => $this->getDefaultBranch(),
|
||||||
|
'lines' => null,
|
||||||
|
);
|
||||||
|
|
||||||
|
$params = $params + $defaults;
|
||||||
|
|
||||||
|
$uri_base = $this->browseURI;
|
||||||
|
$uri_base = rtrim($uri_base, '/');
|
||||||
|
|
||||||
|
$uri_branch = phutil_escape_uri_path_component($params['branch']);
|
||||||
|
|
||||||
|
$uri_path = ltrim($params['path'], '/');
|
||||||
|
$uri_path = phutil_escape_uri($uri_path);
|
||||||
|
|
||||||
|
$uri_lines = null;
|
||||||
|
if ($params['lines']) {
|
||||||
|
$uri_lines = '$'.phutil_escape_uri($params['lines']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: This construction, which includes a branch, is probably wrong for
|
||||||
|
// Subversion.
|
||||||
|
|
||||||
|
return "{$uri_base}/browse/{$uri_branch}/{$uri_path}{$uri_lines}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDefaultBranch() {
|
||||||
|
// TODO: This should read from the remote, and is not correct for
|
||||||
|
// Mercurial anyway, as "default" would be a better default branch.
|
||||||
|
return 'master';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
72
src/ref/ArcanistRevisionRef.php
Normal file
72
src/ref/ArcanistRevisionRef.php
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ArcanistRevisionRef
|
||||||
|
extends ArcanistRef {
|
||||||
|
|
||||||
|
private $parameters;
|
||||||
|
private $sources = array();
|
||||||
|
|
||||||
|
public function getRefIdentifier() {
|
||||||
|
return pht('Revision %s', $this->getMonogram());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function defineHardpoints() {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function newFromConduit(array $dict) {
|
||||||
|
$ref = new self();
|
||||||
|
$ref->parameters = $dict;
|
||||||
|
return $ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMonogram() {
|
||||||
|
return 'D'.$this->getID();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStatusDisplayName() {
|
||||||
|
return idx($this->parameters, 'statusName');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isClosed() {
|
||||||
|
// TODO: This should use sensible constants, not English language
|
||||||
|
// display text.
|
||||||
|
switch ($this->getStatusDisplayName()) {
|
||||||
|
case 'Abandoned':
|
||||||
|
case 'Closed':
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getURI() {
|
||||||
|
return idx($this->parameters, 'uri');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFullName() {
|
||||||
|
return pht('%s: %s', $this->getMonogram(), $this->getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getID() {
|
||||||
|
return idx($this->parameters, 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName() {
|
||||||
|
return idx($this->parameters, 'title');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAuthorPHID() {
|
||||||
|
return idx($this->parameters, 'authorPHID');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addSource(ArcanistRevisionRefSource $source) {
|
||||||
|
$this->sources[] = $source;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSources() {
|
||||||
|
return $this->sources;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
4
src/ref/ArcanistRevisionRefSource.php
Normal file
4
src/ref/ArcanistRevisionRefSource.php
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class ArcanistRevisionRefSource
|
||||||
|
extends Phobject {}
|
122
src/ref/ArcanistWorkingCopyStateRef.php
Normal file
122
src/ref/ArcanistWorkingCopyStateRef.php
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ArcanistWorkingCopyStateRef
|
||||||
|
extends ArcanistRef {
|
||||||
|
|
||||||
|
private $rootDirectory;
|
||||||
|
|
||||||
|
public function getRefIdentifier() {
|
||||||
|
// TODO: This could check attached hardpoints and render something more
|
||||||
|
// insightful.
|
||||||
|
return pht('Working Copy State');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function defineHardpoints() {
|
||||||
|
return array(
|
||||||
|
'commitRef' => array(
|
||||||
|
'type' => 'ArcanistCommitRef',
|
||||||
|
),
|
||||||
|
'branchRef' => array(
|
||||||
|
'type' => 'ArcanistBranchRef',
|
||||||
|
),
|
||||||
|
'revisionRefs' => array(
|
||||||
|
'type' => 'ArcanistRevisionRef',
|
||||||
|
'vector' => true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setRootDirectory($root_directory) {
|
||||||
|
$this->rootDirectory = $root_directory;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRootDirectory() {
|
||||||
|
return $this->rootDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function attachBranchRef(ArcanistBranchRef $branch_ref) {
|
||||||
|
return $this->attachHardpoint('branchRef', $branch_ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBranchRef() {
|
||||||
|
return $this->getHardpoint('branchRef');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setCommitRef(ArcanistCommitRef $commit_ref) {
|
||||||
|
return $this->attachHardpoint('commitRef', $commit_ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCommitRef() {
|
||||||
|
return $this->getHardpoint('commitRef');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRevisionRefs() {
|
||||||
|
return $this->getHardpoint('revisionRefs');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRevisionRef() {
|
||||||
|
if ($this->hasAmbiguousRevisionRefs()) {
|
||||||
|
throw new Exception(
|
||||||
|
pht('State has multiple ambiguous revisions refs.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$refs = $this->getRevisionRefs();
|
||||||
|
if ($refs) {
|
||||||
|
return head($refs);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasAmbiguousRevisionRefs() {
|
||||||
|
return (count($this->getRevisionRefs()) > 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function canReadHardpoint($hardpoint) {
|
||||||
|
switch ($hardpoint) {
|
||||||
|
case 'commitRef':
|
||||||
|
// If we have a branch ref, we can try to read the commit ref from the
|
||||||
|
// branch ref.
|
||||||
|
if ($this->hasAttachedHardpoint('branchRef')) {
|
||||||
|
if ($this->getBranchRef()->hasAttachedHardpoint('commitRef')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function readHardpoint($hardpoint) {
|
||||||
|
switch ($hardpoint) {
|
||||||
|
case 'commitRef':
|
||||||
|
return $this->getBranchRef()->getCommitRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::readHardpoint($hardpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function mergeHardpoint($hardpoint, array $src, array $new) {
|
||||||
|
if ($hardpoint == 'revisionRefs') {
|
||||||
|
$src = mpull($src, null, 'getID');
|
||||||
|
$new = mpull($new, null, 'getID');
|
||||||
|
|
||||||
|
foreach ($new as $id => $ref) {
|
||||||
|
if (isset($src[$id])) {
|
||||||
|
foreach ($ref->getSources() as $source) {
|
||||||
|
$src[$id]->addSource($source);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$src[$id] = $ref;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_values($src);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::mergeHardpoint($hardpoint, $src, $new);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1090,6 +1090,7 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
|
||||||
$result[] = array(
|
$result[] = array(
|
||||||
'current' => ($branch === $current),
|
'current' => ($branch === $current),
|
||||||
'name' => $branch,
|
'name' => $branch,
|
||||||
|
'ref' => $ref,
|
||||||
'hash' => $hash,
|
'hash' => $hash,
|
||||||
'tree' => $tree,
|
'tree' => $tree,
|
||||||
'epoch' => (int)$epoch,
|
'epoch' => (int)$epoch,
|
||||||
|
@ -1102,19 +1103,48 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getAllBranchRefs() {
|
||||||
|
$branches = $this->getAllBranches();
|
||||||
|
|
||||||
|
$refs = array();
|
||||||
|
foreach ($branches as $branch) {
|
||||||
|
$commit_ref = $this->newCommitRef()
|
||||||
|
->setCommitHash($branch['hash'])
|
||||||
|
->setTreeHash($branch['tree'])
|
||||||
|
->setCommitEpoch($branch['epoch'])
|
||||||
|
->attachMessage($branch['text']);
|
||||||
|
|
||||||
|
$refs[] = $this->newBranchRef()
|
||||||
|
->setBranchName($branch['name'])
|
||||||
|
->setRefName($branch['ref'])
|
||||||
|
->setIsCurrentBranch($branch['current'])
|
||||||
|
->attachCommitRef($commit_ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $refs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBaseCommitRef() {
|
||||||
|
$base_commit = $this->getBaseCommit();
|
||||||
|
|
||||||
|
if ($base_commit === self::GIT_MAGIC_ROOT_COMMIT) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$base_message = $this->getCommitMessage($base_commit);
|
||||||
|
|
||||||
|
// TODO: We should also pull the tree hash.
|
||||||
|
|
||||||
|
return $this->newCommitRef()
|
||||||
|
->setCommitHash($base_commit)
|
||||||
|
->attachMessage($base_message);
|
||||||
|
}
|
||||||
|
|
||||||
public function getWorkingCopyRevision() {
|
public function getWorkingCopyRevision() {
|
||||||
list($stdout) = $this->execxLocal('rev-parse HEAD');
|
list($stdout) = $this->execxLocal('rev-parse HEAD');
|
||||||
return rtrim($stdout, "\n");
|
return rtrim($stdout, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUnderlyingWorkingCopyRevision() {
|
|
||||||
list($err, $stdout) = $this->execManualLocal('svn find-rev HEAD');
|
|
||||||
if (!$err && $stdout) {
|
|
||||||
return rtrim($stdout, "\n");
|
|
||||||
}
|
|
||||||
return $this->getWorkingCopyRevision();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function isHistoryDefaultImmutable() {
|
public function isHistoryDefaultImmutable() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -564,6 +564,33 @@ final class ArcanistMercurialAPI extends ArcanistRepositoryAPI {
|
||||||
return $return;
|
return $return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getAllBranchRefs() {
|
||||||
|
$branches = $this->getAllBranches();
|
||||||
|
|
||||||
|
$refs = array();
|
||||||
|
foreach ($branches as $branch) {
|
||||||
|
$refs[] = $this->newBranchRef()
|
||||||
|
->setBranchName($branch['name'])
|
||||||
|
->setIsCurrentBranch($branch['current']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $refs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBaseCommitRef() {
|
||||||
|
$base_commit = $this->getBaseCommit();
|
||||||
|
|
||||||
|
if ($base_commit === 'null') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$base_message = $this->getCommitMessage($base_commit);
|
||||||
|
|
||||||
|
return $this->newCommitRef()
|
||||||
|
->setCommitHash($base_commit)
|
||||||
|
->attachMessage($base_message);
|
||||||
|
}
|
||||||
|
|
||||||
public function hasLocalCommit($commit) {
|
public function hasLocalCommit($commit) {
|
||||||
try {
|
try {
|
||||||
$this->getCanonicalRevisionName($commit);
|
$this->getCanonicalRevisionName($commit);
|
||||||
|
|
|
@ -343,11 +343,6 @@ abstract class ArcanistRepositoryAPI extends Phobject {
|
||||||
array $query);
|
array $query);
|
||||||
abstract public function getRemoteURI();
|
abstract public function getRemoteURI();
|
||||||
|
|
||||||
|
|
||||||
public function getUnderlyingWorkingCopyRevision() {
|
|
||||||
return $this->getWorkingCopyRevision();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getChangedFiles($since_commit) {
|
public function getChangedFiles($since_commit) {
|
||||||
throw new ArcanistCapabilityNotSupportedException($this);
|
throw new ArcanistCapabilityNotSupportedException($this);
|
||||||
}
|
}
|
||||||
|
@ -375,6 +370,14 @@ abstract class ArcanistRepositoryAPI extends Phobject {
|
||||||
return array();
|
return array();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getAllBranchRefs() {
|
||||||
|
throw new ArcanistCapabilityNotSupportedException($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBaseCommitRef() {
|
||||||
|
throw new ArcanistCapabilityNotSupportedException($this);
|
||||||
|
}
|
||||||
|
|
||||||
public function hasLocalCommit($commit) {
|
public function hasLocalCommit($commit) {
|
||||||
throw new ArcanistCapabilityNotSupportedException($this);
|
throw new ArcanistCapabilityNotSupportedException($this);
|
||||||
}
|
}
|
||||||
|
@ -668,4 +671,12 @@ abstract class ArcanistRepositoryAPI extends Phobject {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final public function newCommitRef() {
|
||||||
|
return new ArcanistCommitRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function newBranchRef() {
|
||||||
|
return new ArcanistBranchRef();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,233 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Browse files or objects in the Phabricator web interface.
|
|
||||||
*/
|
|
||||||
final class ArcanistBrowseWorkflow extends ArcanistWorkflow {
|
|
||||||
|
|
||||||
public function getWorkflowName() {
|
|
||||||
return 'browse';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCommandSynopses() {
|
|
||||||
return phutil_console_format(<<<EOTEXT
|
|
||||||
**browse** [__options__] __path__ ...
|
|
||||||
**browse** [__options__] __object__ ...
|
|
||||||
EOTEXT
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCommandHelp() {
|
|
||||||
return phutil_console_format(<<<EOTEXT
|
|
||||||
Supports: git, hg, svn
|
|
||||||
Open a file or object (like a task or revision) in your web browser.
|
|
||||||
|
|
||||||
$ arc browse README # Open a file in Diffusion.
|
|
||||||
$ arc browse T123 # View a task.
|
|
||||||
$ arc browse HEAD # View a symbolic commit.
|
|
||||||
|
|
||||||
Set the 'browser' value using 'arc set-config' to select a browser. If
|
|
||||||
no browser is set, the command will try to guess which browser to use.
|
|
||||||
EOTEXT
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getArguments() {
|
|
||||||
return array(
|
|
||||||
'branch' => array(
|
|
||||||
'param' => 'branch_name',
|
|
||||||
'help' => pht(
|
|
||||||
'Default branch name to view on server. Defaults to "%s".',
|
|
||||||
'master'),
|
|
||||||
),
|
|
||||||
'force' => array(
|
|
||||||
'help' => pht(
|
|
||||||
'Open arguments as paths, even if they do not exist in the '.
|
|
||||||
'working copy.'),
|
|
||||||
),
|
|
||||||
'*' => 'paths',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function desiresWorkingCopy() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function requiresConduit() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function requiresAuthentication() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function desiresRepositoryAPI() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function run() {
|
|
||||||
$console = PhutilConsole::getConsole();
|
|
||||||
|
|
||||||
$is_force = $this->getArgument('force');
|
|
||||||
|
|
||||||
$things = $this->getArgument('paths');
|
|
||||||
if (!$things) {
|
|
||||||
throw new ArcanistUsageException(
|
|
||||||
pht(
|
|
||||||
'Specify one or more paths or objects to browse. Use the command '.
|
|
||||||
'"%s" if you want to browse this directory.',
|
|
||||||
'arc browse .'));
|
|
||||||
}
|
|
||||||
$things = array_fuse($things);
|
|
||||||
|
|
||||||
$objects = $this->getConduit()->callMethodSynchronous(
|
|
||||||
'phid.lookup',
|
|
||||||
array(
|
|
||||||
'names' => array_keys($things),
|
|
||||||
));
|
|
||||||
|
|
||||||
$uris = array();
|
|
||||||
foreach ($objects as $name => $object) {
|
|
||||||
$uris[] = $object['uri'];
|
|
||||||
|
|
||||||
$console->writeOut(
|
|
||||||
pht(
|
|
||||||
'Opening **%s** as an object.',
|
|
||||||
$name)."\n");
|
|
||||||
|
|
||||||
unset($things[$name]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->hasRepositoryAPI()) {
|
|
||||||
$repository_api = $this->getRepositoryAPI();
|
|
||||||
$project_root = $this->getWorkingCopy()->getProjectRoot();
|
|
||||||
|
|
||||||
// First, try to resolve arguments as symbolic commits.
|
|
||||||
|
|
||||||
$commits = array();
|
|
||||||
foreach ($things as $key => $thing) {
|
|
||||||
if ($thing == '.') {
|
|
||||||
// Git resolves '.' like HEAD, but it should be interpreted to mean
|
|
||||||
// "the current directory". Just skip resolution and fall through.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$commit = $repository_api->getCanonicalRevisionName($thing);
|
|
||||||
if ($commit) {
|
|
||||||
$commits[$commit] = $key;
|
|
||||||
}
|
|
||||||
} catch (Exception $ex) {
|
|
||||||
// Ignore.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($commits) {
|
|
||||||
$commit_info = $this->getConduit()->callMethodSynchronous(
|
|
||||||
'diffusion.querycommits',
|
|
||||||
array(
|
|
||||||
'repositoryPHID' => $this->getRepositoryPHID(),
|
|
||||||
'names' => array_keys($commits),
|
|
||||||
));
|
|
||||||
|
|
||||||
foreach ($commit_info['identifierMap'] as $ckey => $cphid) {
|
|
||||||
$thing = $commits[$ckey];
|
|
||||||
unset($things[$thing]);
|
|
||||||
|
|
||||||
$uris[] = $commit_info['data'][$cphid]['uri'];
|
|
||||||
|
|
||||||
$console->writeOut(
|
|
||||||
pht(
|
|
||||||
'Opening **%s** as a commit.',
|
|
||||||
$thing)."\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we fail, try to resolve them as paths.
|
|
||||||
|
|
||||||
foreach ($things as $key => $path) {
|
|
||||||
$lines = null;
|
|
||||||
$parts = explode(':', $path);
|
|
||||||
if (count($parts) > 1) {
|
|
||||||
$lines = array_pop($parts);
|
|
||||||
}
|
|
||||||
$path = implode(':', $parts);
|
|
||||||
|
|
||||||
$full_path = Filesystem::resolvePath($path);
|
|
||||||
|
|
||||||
if (!$is_force && !Filesystem::pathExists($full_path)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$console->writeOut(
|
|
||||||
pht(
|
|
||||||
'Opening **%s** as a repository path.',
|
|
||||||
$key)."\n");
|
|
||||||
|
|
||||||
unset($things[$key]);
|
|
||||||
|
|
||||||
if ($full_path == $project_root) {
|
|
||||||
$path = '';
|
|
||||||
} else {
|
|
||||||
$path = Filesystem::readablePath($full_path, $project_root);
|
|
||||||
}
|
|
||||||
|
|
||||||
$base_uri = $this->getBaseURI();
|
|
||||||
$uri = $base_uri.$path;
|
|
||||||
|
|
||||||
if ($lines) {
|
|
||||||
$uri = $uri.'$'.$lines;
|
|
||||||
}
|
|
||||||
|
|
||||||
$uris[] = $uri;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ($things) {
|
|
||||||
$console->writeOut(
|
|
||||||
"%s\n",
|
|
||||||
pht(
|
|
||||||
"The current working directory is not a repository working ".
|
|
||||||
"copy, so remaining arguments can not be resolved as paths or ".
|
|
||||||
"commits. To browse paths or symbolic commits in Diffusion, run ".
|
|
||||||
"'%s' from inside a working copy.",
|
|
||||||
'arc browse'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($things as $thing) {
|
|
||||||
$console->writeOut(
|
|
||||||
"%s\n",
|
|
||||||
pht(
|
|
||||||
'Unable to find an object named **%s**, no such commit exists in '.
|
|
||||||
'the remote, and no such path exists in the working copy. Use '.
|
|
||||||
'__%s__ to treat this as a path anyway.',
|
|
||||||
$thing,
|
|
||||||
'--force'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($uris) {
|
|
||||||
$this->openURIsInBrowser($uris);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getBaseURI() {
|
|
||||||
$repo_uri = $this->getRepositoryURI();
|
|
||||||
if ($repo_uri === null) {
|
|
||||||
throw new ArcanistUsageException(
|
|
||||||
pht(
|
|
||||||
'arc is unable to determine which repository in Diffusion '.
|
|
||||||
'this working copy belongs to. Use "%s" to understand how '.
|
|
||||||
'%s looks for a repository.',
|
|
||||||
'arc which',
|
|
||||||
'arc'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$branch = $this->getArgument('branch', 'master');
|
|
||||||
$branch = phutil_escape_uri_path_component($branch);
|
|
||||||
|
|
||||||
return $repo_uri.'browse/'.$branch.'/';
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -2017,6 +2017,15 @@ EOTEXT
|
||||||
$faux_message[] = pht('CC: %s', $this->getArgument('cc'));
|
$faux_message[] = pht('CC: %s', $this->getArgument('cc'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: For now, this isn't a real field, so it just ends up as the first
|
||||||
|
// part of the summary.
|
||||||
|
$depends_ref = $this->getDependsOnRevisionRef();
|
||||||
|
if ($depends_ref) {
|
||||||
|
$faux_message[] = pht(
|
||||||
|
'Depends on %s. ',
|
||||||
|
$depends_ref->getMonogram());
|
||||||
|
}
|
||||||
|
|
||||||
// See T12069. After T10312, the first line of a message is always parsed
|
// See T12069. After T10312, the first line of a message is always parsed
|
||||||
// as a title. Add a placeholder so "Reviewers" and "CC" are never the
|
// as a title. Add a placeholder so "Reviewers" and "CC" are never the
|
||||||
// first line.
|
// first line.
|
||||||
|
@ -3030,4 +3039,46 @@ EOTEXT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getDependsOnRevisionRef() {
|
||||||
|
$api = $this->getRepositoryAPI();
|
||||||
|
$base_ref = $api->getBaseCommitRef();
|
||||||
|
|
||||||
|
$state_ref = $this->newWorkingCopyStateRef()
|
||||||
|
->setCommitRef($base_ref);
|
||||||
|
|
||||||
|
$this->newRefQuery(array($state_ref))
|
||||||
|
->needHardpoints(
|
||||||
|
array(
|
||||||
|
'revisionRefs',
|
||||||
|
))
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$revision_refs = $state_ref->getRevisionRefs();
|
||||||
|
$viewer_phid = $this->getUserPHID();
|
||||||
|
|
||||||
|
foreach ($revision_refs as $key => $revision_ref) {
|
||||||
|
// Don't automatically depend on closed revisions.
|
||||||
|
if ($revision_ref->isClosed()) {
|
||||||
|
unset($revision_refs[$key]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't automatically depend on revisions authored by other users.
|
||||||
|
if ($revision_ref->getAuthorPHID() != $viewer_phid) {
|
||||||
|
unset($revision_refs[$key]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$revision_refs) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count($revision_refs) > 1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return head($revision_refs);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,18 +38,10 @@ EOTEXT
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function requiresConduit() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function requiresRepositoryAPI() {
|
public function requiresRepositoryAPI() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function requiresAuthentication() {
|
|
||||||
return !$this->getArgument('branch');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getArguments() {
|
public function getArguments() {
|
||||||
return array(
|
return array(
|
||||||
'view-all' => array(
|
'view-all' => array(
|
||||||
|
@ -86,15 +78,29 @@ EOTEXT
|
||||||
return $this->checkoutBranch($names);
|
return $this->checkoutBranch($names);
|
||||||
}
|
}
|
||||||
|
|
||||||
$branches = $repository_api->getAllBranches();
|
// TODO: Everything in this whole workflow that says "branch" means
|
||||||
|
// "bookmark" in Mercurial.
|
||||||
|
|
||||||
|
$branches = $repository_api->getAllBranchRefs();
|
||||||
if (!$branches) {
|
if (!$branches) {
|
||||||
throw new ArcanistUsageException(
|
throw new ArcanistUsageException(
|
||||||
pht('No branches in this working copy.'));
|
pht('No branches in this working copy.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$branches = $this->loadCommitInfo($branches);
|
$states = array();
|
||||||
$revisions = $this->loadRevisions($branches);
|
foreach ($branches as $branch) {
|
||||||
$this->printBranches($branches, $revisions);
|
$states[] = $this->newWorkingCopyStateRef()
|
||||||
|
->attachBranchRef($branch);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->newRefQuery($states)
|
||||||
|
->needHardpoints(
|
||||||
|
array(
|
||||||
|
'revisionRefs',
|
||||||
|
))
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$this->printBranches($states);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -125,8 +131,7 @@ EOTEXT
|
||||||
if ($err) {
|
if ($err) {
|
||||||
$match = null;
|
$match = null;
|
||||||
if (preg_match('/^D(\d+)$/', $name, $match)) {
|
if (preg_match('/^D(\d+)$/', $name, $match)) {
|
||||||
try {
|
$diff = $this->getConduitEngine()->resolveCall(
|
||||||
$diff = $this->getConduit()->callMethodSynchronous(
|
|
||||||
'differential.querydiffs',
|
'differential.querydiffs',
|
||||||
array(
|
array(
|
||||||
'revisionIDs' => array($match[1]),
|
'revisionIDs' => array($match[1]),
|
||||||
|
@ -139,7 +144,6 @@ EOTEXT
|
||||||
$command,
|
$command,
|
||||||
$name);
|
$name);
|
||||||
}
|
}
|
||||||
} catch (ConduitClientException $ex) {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,99 +175,7 @@ EOTEXT
|
||||||
return $err;
|
return $err;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function loadCommitInfo(array $branches) {
|
private function printBranches(array $states) {
|
||||||
$repository_api = $this->getRepositoryAPI();
|
|
||||||
|
|
||||||
$branches = ipull($branches, null, 'name');
|
|
||||||
|
|
||||||
if ($repository_api instanceof ArcanistMercurialAPI) {
|
|
||||||
$futures = array();
|
|
||||||
foreach ($branches as $branch) {
|
|
||||||
$futures[$branch['name']] = $repository_api->execFutureLocal(
|
|
||||||
'log -l 1 --template %s -r %s',
|
|
||||||
"{node}\1{date|hgdate}\1{p1node}\1{desc|firstline}\1{desc}",
|
|
||||||
hgsprintf('%s', $branch['name']));
|
|
||||||
}
|
|
||||||
|
|
||||||
$futures = id(new FutureIterator($futures))
|
|
||||||
->limit(16);
|
|
||||||
foreach ($futures as $name => $future) {
|
|
||||||
list($info) = $future->resolvex();
|
|
||||||
|
|
||||||
$fields = explode("\1", trim($info), 5);
|
|
||||||
list($hash, $epoch, $tree, $desc, $text) = $fields;
|
|
||||||
|
|
||||||
$branches[$name] += array(
|
|
||||||
'hash' => $hash,
|
|
||||||
'desc' => $desc,
|
|
||||||
'tree' => $tree,
|
|
||||||
'epoch' => (int)$epoch,
|
|
||||||
'text' => $text,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($branches as $name => $branch) {
|
|
||||||
$text = $branch['text'];
|
|
||||||
|
|
||||||
try {
|
|
||||||
$message = ArcanistDifferentialCommitMessage::newFromRawCorpus($text);
|
|
||||||
$id = $message->getRevisionID();
|
|
||||||
|
|
||||||
$branch['revisionID'] = $id;
|
|
||||||
} catch (ArcanistUsageException $ex) {
|
|
||||||
// In case of invalid commit message which fails the parsing,
|
|
||||||
// do nothing.
|
|
||||||
$branch['revisionID'] = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$branches[$name] = $branch;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $branches;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function loadRevisions(array $branches) {
|
|
||||||
$ids = array();
|
|
||||||
$hashes = array();
|
|
||||||
|
|
||||||
foreach ($branches as $branch) {
|
|
||||||
if ($branch['revisionID']) {
|
|
||||||
$ids[] = $branch['revisionID'];
|
|
||||||
}
|
|
||||||
$hashes[] = array('gtcm', $branch['hash']);
|
|
||||||
$hashes[] = array('gttr', $branch['tree']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$calls = array();
|
|
||||||
|
|
||||||
if ($ids) {
|
|
||||||
$calls[] = $this->getConduit()->callMethod(
|
|
||||||
'differential.query',
|
|
||||||
array(
|
|
||||||
'ids' => $ids,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($hashes) {
|
|
||||||
$calls[] = $this->getConduit()->callMethod(
|
|
||||||
'differential.query',
|
|
||||||
array(
|
|
||||||
'commitHashes' => $hashes,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
$results = array();
|
|
||||||
foreach (new FutureIterator($calls) as $call) {
|
|
||||||
$results[] = $call->resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
return array_mergev($results);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function printBranches(array $branches, array $revisions) {
|
|
||||||
$revisions = ipull($revisions, null, 'id');
|
|
||||||
|
|
||||||
static $color_map = array(
|
static $color_map = array(
|
||||||
'Closed' => 'cyan',
|
'Closed' => 'cyan',
|
||||||
'Needs Review' => 'magenta',
|
'Needs Review' => 'magenta',
|
||||||
|
@ -282,48 +194,45 @@ EOTEXT
|
||||||
);
|
);
|
||||||
|
|
||||||
$out = array();
|
$out = array();
|
||||||
foreach ($branches as $branch) {
|
foreach ($states as $state) {
|
||||||
$revision = idx($revisions, idx($branch, 'revisionID'));
|
$branch = $state->getBranchRef();
|
||||||
|
|
||||||
// If we haven't identified a revision by ID, try to identify it by hash.
|
$revision = null;
|
||||||
if (!$revision) {
|
if ($state->hasAmbiguousRevisionRefs()) {
|
||||||
foreach ($revisions as $rev) {
|
$status = pht('Ambiguous Revision');
|
||||||
$hashes = idx($rev, 'hashes', array());
|
} else {
|
||||||
foreach ($hashes as $hash) {
|
$revision = $state->getRevisionRef();
|
||||||
if (($hash[0] == 'gtcm' && $hash[1] == $branch['hash']) ||
|
if ($revision) {
|
||||||
($hash[0] == 'gttr' && $hash[1] == $branch['tree'])) {
|
$status = $revision->getStatusDisplayName();
|
||||||
$revision = $rev;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($revision) {
|
|
||||||
$desc = 'D'.$revision['id'].': '.$revision['title'];
|
|
||||||
$status = $revision['statusName'];
|
|
||||||
} else {
|
} else {
|
||||||
$desc = $branch['desc'];
|
|
||||||
$status = pht('No Revision');
|
$status = pht('No Revision');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!$this->getArgument('view-all') && !$branch['current']) {
|
if (!$this->getArgument('view-all') && !$branch->getIsCurrentBranch()) {
|
||||||
if ($status == 'Closed' || $status == 'Abandoned') {
|
if ($status == 'Closed' || $status == 'Abandoned') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$epoch = $branch['epoch'];
|
$commit = $branch->getCommitRef();
|
||||||
|
$epoch = $commit->getCommitEpoch();
|
||||||
|
|
||||||
$color = idx($color_map, $status, 'default');
|
$color = idx($color_map, $status, 'default');
|
||||||
$ssort = sprintf('%d%012d', idx($ssort_map, $status, 0), $epoch);
|
$ssort = sprintf('%d%012d', idx($ssort_map, $status, 0), $epoch);
|
||||||
|
|
||||||
|
if ($revision) {
|
||||||
|
$desc = $revision->getFullName();
|
||||||
|
} else {
|
||||||
|
$desc = $commit->getSummary();
|
||||||
|
}
|
||||||
|
|
||||||
$out[] = array(
|
$out[] = array(
|
||||||
'name' => $branch['name'],
|
'name' => $branch->getBranchName(),
|
||||||
'current' => $branch['current'],
|
'current' => $branch->getIsCurrentBranch(),
|
||||||
'status' => $status,
|
'status' => $status,
|
||||||
'desc' => $desc,
|
'desc' => $desc,
|
||||||
'revision' => $revision ? $revision['id'] : null,
|
'revision' => $revision ? $revision->getID() : null,
|
||||||
'color' => $color,
|
'color' => $color,
|
||||||
'esort' => $epoch,
|
'esort' => $epoch,
|
||||||
'epoch' => $epoch,
|
'epoch' => $epoch,
|
||||||
|
|
|
@ -29,6 +29,13 @@ EOTEXT
|
||||||
'arcanist' => dirname(phutil_get_library_root('arcanist')),
|
'arcanist' => dirname(phutil_get_library_root('arcanist')),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$supported_branches = array(
|
||||||
|
'master',
|
||||||
|
'stable',
|
||||||
|
'experimental',
|
||||||
|
);
|
||||||
|
$supported_branches = array_fuse($supported_branches);
|
||||||
|
|
||||||
foreach ($roots as $lib => $root) {
|
foreach ($roots as $lib => $root) {
|
||||||
echo phutil_console_format(
|
echo phutil_console_format(
|
||||||
"%s\n",
|
"%s\n",
|
||||||
|
@ -75,18 +82,16 @@ EOTEXT
|
||||||
}
|
}
|
||||||
|
|
||||||
$branch_name = $repository->getBranchName();
|
$branch_name = $repository->getBranchName();
|
||||||
if ($branch_name != 'master' && $branch_name != 'stable') {
|
if (!isset($supported_branches[$branch_name])) {
|
||||||
throw new ArcanistUsageException(
|
throw new ArcanistUsageException(
|
||||||
pht(
|
pht(
|
||||||
"%s must be on either branch '%s' or '%s' to be automatically ".
|
'Library "%s" (in "%s") is on branch "%s", but this branch is '.
|
||||||
"upgraded. ".
|
'not supported for automatic upgrades. Supported branches are: '.
|
||||||
"This copy of %s (in '%s') is on branch '%s'.",
|
'%s.',
|
||||||
$lib,
|
|
||||||
'master',
|
|
||||||
'stable',
|
|
||||||
$lib,
|
$lib,
|
||||||
$root,
|
$root,
|
||||||
$branch_name));
|
$branch_name,
|
||||||
|
implode(', ', array_keys($supported_branches))));
|
||||||
}
|
}
|
||||||
|
|
||||||
chdir($root);
|
chdir($root);
|
||||||
|
|
|
@ -62,6 +62,7 @@ abstract class ArcanistWorkflow extends Phobject {
|
||||||
private $projectInfo;
|
private $projectInfo;
|
||||||
private $repositoryInfo;
|
private $repositoryInfo;
|
||||||
private $repositoryReasons;
|
private $repositoryReasons;
|
||||||
|
private $repositoryRef;
|
||||||
|
|
||||||
private $arcanistConfiguration;
|
private $arcanistConfiguration;
|
||||||
private $parentWorkflow;
|
private $parentWorkflow;
|
||||||
|
@ -69,6 +70,7 @@ abstract class ArcanistWorkflow extends Phobject {
|
||||||
private $repositoryVersion;
|
private $repositoryVersion;
|
||||||
|
|
||||||
private $changeCache = array();
|
private $changeCache = array();
|
||||||
|
private $conduitEngine;
|
||||||
|
|
||||||
|
|
||||||
public function __construct() {}
|
public function __construct() {}
|
||||||
|
@ -582,6 +584,7 @@ abstract class ArcanistWorkflow extends Phobject {
|
||||||
$arc_config = $this->getArcanistConfiguration();
|
$arc_config = $this->getArcanistConfiguration();
|
||||||
$workflow = $arc_config->buildWorkflow($command);
|
$workflow = $arc_config->buildWorkflow($command);
|
||||||
$workflow->setParentWorkflow($this);
|
$workflow->setParentWorkflow($this);
|
||||||
|
$workflow->setConduitEngine($this->getConduitEngine());
|
||||||
$workflow->setCommand($command);
|
$workflow->setCommand($command);
|
||||||
$workflow->setConfigurationManager($this->getConfigurationManager());
|
$workflow->setConfigurationManager($this->getConfigurationManager());
|
||||||
|
|
||||||
|
@ -1773,9 +1776,9 @@ abstract class ArcanistWorkflow extends Phobject {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$results = $this->getConduit()->callMethodSynchronous(
|
$method = 'repository.query';
|
||||||
'repository.query',
|
$results = $this->getConduitEngine()->newCall($method, $query)
|
||||||
$query);
|
->resolve();
|
||||||
} catch (ConduitClientException $ex) {
|
} catch (ConduitClientException $ex) {
|
||||||
if ($ex->getErrorCode() == 'ERR-CONDUIT-CALL') {
|
if ($ex->getErrorCode() == 'ERR-CONDUIT-CALL') {
|
||||||
$reasons[] = pht(
|
$reasons[] = pht(
|
||||||
|
@ -2068,5 +2071,68 @@ abstract class ArcanistWorkflow extends Phobject {
|
||||||
return $map;
|
return $map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final public function setConduitEngine(
|
||||||
|
ArcanistConduitEngine $conduit_engine) {
|
||||||
|
$this->conduitEngine = $conduit_engine;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function getConduitEngine() {
|
||||||
|
return $this->conduitEngine;
|
||||||
|
}
|
||||||
|
|
||||||
|
final protected function newWorkingCopyStateRef() {
|
||||||
|
$ref = new ArcanistWorkingCopyStateRef();
|
||||||
|
|
||||||
|
$working_copy = $this->getWorkingCopy();
|
||||||
|
$ref->setRootDirectory($working_copy->getProjectRoot());
|
||||||
|
|
||||||
|
return $ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
final protected function newRefQuery(array $refs) {
|
||||||
|
assert_instances_of($refs, 'ArcanistRef');
|
||||||
|
|
||||||
|
$query = id(new ArcanistRefQuery())
|
||||||
|
->setConduitEngine($this->getConduitEngine())
|
||||||
|
->setRefs($refs);
|
||||||
|
|
||||||
|
if ($this->hasRepositoryAPI()) {
|
||||||
|
$query->setRepositoryAPI($this->getRepositoryAPI());
|
||||||
|
}
|
||||||
|
|
||||||
|
$repository_ref = $this->getRepositoryRef();
|
||||||
|
if ($repository_ref) {
|
||||||
|
$query->setRepositoryRef($repository_ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
$working_copy = $this->getConfigurationManager()->getWorkingCopyIdentity();
|
||||||
|
if ($working_copy) {
|
||||||
|
$working_ref = $this->newWorkingCopyStateRef();
|
||||||
|
$query->setWorkingCopyRef($working_ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function getRepositoryRef() {
|
||||||
|
if (!$this->getConfigurationManager()->getWorkingCopyIdentity()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->repositoryAPI) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->repositoryRef) {
|
||||||
|
$ref = id(new ArcanistRepositoryRef())
|
||||||
|
->setPHID($this->getRepositoryPHID())
|
||||||
|
->setBrowseURI($this->getRepositoryURI());
|
||||||
|
|
||||||
|
$this->repositoryRef = $ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->repositoryRef;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue