1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2025-01-15 17:21:09 +01:00

[Wilds] Remove all linters and test cases not used by Arcanist

Summary: Ref T13098. I may restore some of these later, but this was a big obvious step in getting `arc unit` passing. I'd generally like these to live in third party libraries some day, if not immediately.

Test Plan: No failing tests after D19716.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13098

Differential Revision: https://secure.phabricator.com/D19717
This commit is contained in:
epriestley 2018-09-27 13:27:08 -07:00
parent 22cf774ae1
commit 529b21844b
194 changed files with 2 additions and 8101 deletions

View file

@ -97,9 +97,6 @@ phutil_register_library_map(array(
'ArcanistBuildRef' => 'ref/ArcanistBuildRef.php',
'ArcanistBundle' => 'parser/ArcanistBundle.php',
'ArcanistBundleTestCase' => 'parser/__tests__/ArcanistBundleTestCase.php',
'ArcanistCSSLintLinter' => 'lint/linter/ArcanistCSSLintLinter.php',
'ArcanistCSSLintLinterTestCase' => 'lint/linter/__tests__/ArcanistCSSLintLinterTestCase.php',
'ArcanistCSharpLinter' => 'lint/linter/ArcanistCSharpLinter.php',
'ArcanistCallConduitWorkflow' => 'workflow/ArcanistCallConduitWorkflow.php',
'ArcanistCallParenthesesXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistCallParenthesesXHPASTLinterRule.php',
'ArcanistCallParenthesesXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistCallParenthesesXHPASTLinterRuleTestCase.php',
@ -120,10 +117,6 @@ phutil_register_library_map(array(
'ArcanistClassNameLiteralXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistClassNameLiteralXHPASTLinterRuleTestCase.php',
'ArcanistCloseRevisionWorkflow' => 'workflow/ArcanistCloseRevisionWorkflow.php',
'ArcanistCloseWorkflow' => 'workflow/ArcanistCloseWorkflow.php',
'ArcanistClosureLinter' => 'lint/linter/ArcanistClosureLinter.php',
'ArcanistClosureLinterTestCase' => 'lint/linter/__tests__/ArcanistClosureLinterTestCase.php',
'ArcanistCoffeeLintLinter' => 'lint/linter/ArcanistCoffeeLintLinter.php',
'ArcanistCoffeeLintLinterTestCase' => 'lint/linter/__tests__/ArcanistCoffeeLintLinterTestCase.php',
'ArcanistCommentRemover' => 'parser/ArcanistCommentRemover.php',
'ArcanistCommentRemoverTestCase' => 'parser/__tests__/ArcanistCommentRemoverTestCase.php',
'ArcanistCommentSpacingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistCommentSpacingXHPASTLinterRule.php',
@ -133,7 +126,6 @@ phutil_register_library_map(array(
'ArcanistCommitUpstreamHardpointLoader' => 'loader/ArcanistCommitUpstreamHardpointLoader.php',
'ArcanistCommitWorkflow' => 'workflow/ArcanistCommitWorkflow.php',
'ArcanistCompilerLintRenderer' => 'lint/renderer/ArcanistCompilerLintRenderer.php',
'ArcanistComposerLinter' => 'lint/linter/ArcanistComposerLinter.php',
'ArcanistComprehensiveLintEngine' => 'lint/engine/ArcanistComprehensiveLintEngine.php',
'ArcanistConcatenationOperatorXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistConcatenationOperatorXHPASTLinterRule.php',
'ArcanistConcatenationOperatorXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistConcatenationOperatorXHPASTLinterRuleTestCase.php',
@ -155,10 +147,6 @@ phutil_register_library_map(array(
'ArcanistControlStatementSpacingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistControlStatementSpacingXHPASTLinterRule.php',
'ArcanistControlStatementSpacingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistControlStatementSpacingXHPASTLinterRuleTestCase.php',
'ArcanistCoverWorkflow' => 'workflow/ArcanistCoverWorkflow.php',
'ArcanistCppcheckLinter' => 'lint/linter/ArcanistCppcheckLinter.php',
'ArcanistCppcheckLinterTestCase' => 'lint/linter/__tests__/ArcanistCppcheckLinterTestCase.php',
'ArcanistCpplintLinter' => 'lint/linter/ArcanistCpplintLinter.php',
'ArcanistCpplintLinterTestCase' => 'lint/linter/__tests__/ArcanistCpplintLinterTestCase.php',
'ArcanistCurlyBraceArrayIndexXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistCurlyBraceArrayIndexXHPASTLinterRule.php',
'ArcanistCurlyBraceArrayIndexXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistCurlyBraceArrayIndexXHPASTLinterRuleTestCase.php',
'ArcanistDeclarationParenthesesXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistDeclarationParenthesesXHPASTLinterRule.php',
@ -202,8 +190,6 @@ phutil_register_library_map(array(
'ArcanistExitExpressionXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistExitExpressionXHPASTLinterRule.php',
'ArcanistExitExpressionXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistExitExpressionXHPASTLinterRuleTestCase.php',
'ArcanistExportWorkflow' => 'workflow/ArcanistExportWorkflow.php',
'ArcanistExternalLinter' => 'lint/linter/ArcanistExternalLinter.php',
'ArcanistExternalLinterTestCase' => 'lint/linter/__tests__/ArcanistExternalLinterTestCase.php',
'ArcanistExtractUseXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistExtractUseXHPASTLinterRule.php',
'ArcanistExtractUseXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistExtractUseXHPASTLinterRuleTestCase.php',
'ArcanistFeatureWorkflow' => 'workflow/ArcanistFeatureWorkflow.php',
@ -214,13 +200,10 @@ phutil_register_library_map(array(
'ArcanistFilenameLinterTestCase' => 'lint/linter/__tests__/ArcanistFilenameLinterTestCase.php',
'ArcanistFilesystemConfigurationSource' => 'config/source/ArcanistFilesystemConfigurationSource.php',
'ArcanistFlagWorkflow' => 'workflow/ArcanistFlagWorkflow.php',
'ArcanistFlake8Linter' => 'lint/linter/ArcanistFlake8Linter.php',
'ArcanistFlake8LinterTestCase' => 'lint/linter/__tests__/ArcanistFlake8LinterTestCase.php',
'ArcanistFormattedStringXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistFormattedStringXHPASTLinterRule.php',
'ArcanistFormattedStringXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistFormattedStringXHPASTLinterRuleTestCase.php',
'ArcanistFunctionCallShouldBeTypeCastXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistFunctionCallShouldBeTypeCastXHPASTLinterRule.php',
'ArcanistFunctionCallShouldBeTypeCastXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistFunctionCallShouldBeTypeCastXHPASTLinterRuleTestCase.php',
'ArcanistFutureLinter' => 'lint/linter/ArcanistFutureLinter.php',
'ArcanistGeneratedLinter' => 'lint/linter/ArcanistGeneratedLinter.php',
'ArcanistGeneratedLinterTestCase' => 'lint/linter/__tests__/ArcanistGeneratedLinterTestCase.php',
'ArcanistGetConfigWorkflow' => 'toolset/workflow/ArcanistGetConfigWorkflow.php',
@ -233,12 +216,8 @@ phutil_register_library_map(array(
'ArcanistGitWorkingCopy' => 'workingcopy/ArcanistGitWorkingCopy.php',
'ArcanistGlobalVariableXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistGlobalVariableXHPASTLinterRule.php',
'ArcanistGlobalVariableXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistGlobalVariableXHPASTLinterRuleTestCase.php',
'ArcanistGoLintLinter' => 'lint/linter/ArcanistGoLintLinter.php',
'ArcanistGoLintLinterTestCase' => 'lint/linter/__tests__/ArcanistGoLintLinterTestCase.php',
'ArcanistGoTestResultParser' => 'unit/parser/ArcanistGoTestResultParser.php',
'ArcanistGoTestResultParserTestCase' => 'unit/parser/__tests__/ArcanistGoTestResultParserTestCase.php',
'ArcanistHLintLinter' => 'lint/linter/ArcanistHLintLinter.php',
'ArcanistHLintLinterTestCase' => 'lint/linter/__tests__/ArcanistHLintLinterTestCase.php',
'ArcanistHardpointLoader' => 'loader/ArcanistHardpointLoader.php',
'ArcanistHelpWorkflow' => 'toolset/workflow/ArcanistHelpWorkflow.php',
'ArcanistHexadecimalNumericScalarCasingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistHexadecimalNumericScalarCasingXHPASTLinterRule.php',
@ -253,7 +232,7 @@ phutil_register_library_map(array(
'ArcanistImplicitFallthroughXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistImplicitFallthroughXHPASTLinterRuleTestCase.php',
'ArcanistImplicitVisibilityXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistImplicitVisibilityXHPASTLinterRule.php',
'ArcanistImplicitVisibilityXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistImplicitVisibilityXHPASTLinterRuleTestCase.php',
'ArcanistInlineHTMLXHPASTLinterRule' => 'lint/linter/ArcanistInlineHTMLXHPASTLinterRule.php',
'ArcanistInlineHTMLXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistInlineHTMLXHPASTLinterRule.php',
'ArcanistInlineHTMLXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistInlineHTMLXHPASTLinterRuleTestCase.php',
'ArcanistInnerFunctionXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistInnerFunctionXHPASTLinterRule.php',
'ArcanistInnerFunctionXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistInnerFunctionXHPASTLinterRuleTestCase.php',
@ -272,16 +251,10 @@ phutil_register_library_map(array(
'ArcanistInvalidOctalNumericScalarXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistInvalidOctalNumericScalarXHPASTLinterRuleTestCase.php',
'ArcanistIsAShouldBeInstanceOfXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistIsAShouldBeInstanceOfXHPASTLinterRule.php',
'ArcanistIsAShouldBeInstanceOfXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistIsAShouldBeInstanceOfXHPASTLinterRuleTestCase.php',
'ArcanistJSHintLinter' => 'lint/linter/ArcanistJSHintLinter.php',
'ArcanistJSHintLinterTestCase' => 'lint/linter/__tests__/ArcanistJSHintLinterTestCase.php',
'ArcanistJSONLintLinter' => 'lint/linter/ArcanistJSONLintLinter.php',
'ArcanistJSONLintLinterTestCase' => 'lint/linter/__tests__/ArcanistJSONLintLinterTestCase.php',
'ArcanistJSONLintRenderer' => 'lint/renderer/ArcanistJSONLintRenderer.php',
'ArcanistJSONLinter' => 'lint/linter/ArcanistJSONLinter.php',
'ArcanistJSONLinterTestCase' => 'lint/linter/__tests__/ArcanistJSONLinterTestCase.php',
'ArcanistJSONUnitSink' => 'unit/sink/ArcanistJSONUnitSink.php',
'ArcanistJscsLinter' => 'lint/linter/ArcanistJscsLinter.php',
'ArcanistJscsLinterTestCase' => 'lint/linter/__tests__/ArcanistJscsLinterTestCase.php',
'ArcanistKeywordCasingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistKeywordCasingXHPASTLinterRule.php',
'ArcanistKeywordCasingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistKeywordCasingXHPASTLinterRuleTestCase.php',
'ArcanistLambdaFuncFunctionXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistLambdaFuncFunctionXHPASTLinterRule.php',
@ -290,8 +263,6 @@ phutil_register_library_map(array(
'ArcanistLandWorkflow' => 'workflow/ArcanistLandWorkflow.php',
'ArcanistLanguageConstructParenthesesXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistLanguageConstructParenthesesXHPASTLinterRule.php',
'ArcanistLanguageConstructParenthesesXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistLanguageConstructParenthesesXHPASTLinterRuleTestCase.php',
'ArcanistLesscLinter' => 'lint/linter/ArcanistLesscLinter.php',
'ArcanistLesscLinterTestCase' => 'lint/linter/__tests__/ArcanistLesscLinterTestCase.php',
'ArcanistLiberateWorkflow' => 'workflow/ArcanistLiberateWorkflow.php',
'ArcanistLintEngine' => 'lint/engine/ArcanistLintEngine.php',
'ArcanistLintMessage' => 'lint/ArcanistLintMessage.php',
@ -348,8 +319,6 @@ phutil_register_library_map(array(
'ArcanistNoneLintRenderer' => 'lint/renderer/ArcanistNoneLintRenderer.php',
'ArcanistObjectOperatorSpacingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistObjectOperatorSpacingXHPASTLinterRule.php',
'ArcanistObjectOperatorSpacingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistObjectOperatorSpacingXHPASTLinterRuleTestCase.php',
'ArcanistPEP8Linter' => 'lint/linter/ArcanistPEP8Linter.php',
'ArcanistPEP8LinterTestCase' => 'lint/linter/__tests__/ArcanistPEP8LinterTestCase.php',
'ArcanistPHPCloseTagXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistPHPCloseTagXHPASTLinterRule.php',
'ArcanistPHPCloseTagXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistPHPCloseTagXHPASTLinterRuleTestCase.php',
'ArcanistPHPCompatibilityXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistPHPCompatibilityXHPASTLinterRule.php',
@ -371,10 +340,6 @@ phutil_register_library_map(array(
'ArcanistPasteWorkflow' => 'workflow/ArcanistPasteWorkflow.php',
'ArcanistPatchWorkflow' => 'workflow/ArcanistPatchWorkflow.php',
'ArcanistPhageToolset' => 'toolset/ArcanistPhageToolset.php',
'ArcanistPhpLinter' => 'lint/linter/ArcanistPhpLinter.php',
'ArcanistPhpLinterTestCase' => 'lint/linter/__tests__/ArcanistPhpLinterTestCase.php',
'ArcanistPhpcsLinter' => 'lint/linter/ArcanistPhpcsLinter.php',
'ArcanistPhpcsLinterTestCase' => 'lint/linter/__tests__/ArcanistPhpcsLinterTestCase.php',
'ArcanistPhpunitTestResultParser' => 'unit/parser/ArcanistPhpunitTestResultParser.php',
'ArcanistPhrequentWorkflow' => 'workflow/ArcanistPhrequentWorkflow.php',
'ArcanistPhutilLibraryLinter' => 'lint/linter/ArcanistPhutilLibraryLinter.php',
@ -389,12 +354,6 @@ phutil_register_library_map(array(
'ArcanistPromptsWorkflow' => 'toolset/workflow/ArcanistPromptsWorkflow.php',
'ArcanistPublicPropertyXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistPublicPropertyXHPASTLinterRule.php',
'ArcanistPublicPropertyXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistPublicPropertyXHPASTLinterRuleTestCase.php',
'ArcanistPuppetLintLinter' => 'lint/linter/ArcanistPuppetLintLinter.php',
'ArcanistPuppetLintLinterTestCase' => 'lint/linter/__tests__/ArcanistPuppetLintLinterTestCase.php',
'ArcanistPyFlakesLinter' => 'lint/linter/ArcanistPyFlakesLinter.php',
'ArcanistPyFlakesLinterTestCase' => 'lint/linter/__tests__/ArcanistPyFlakesLinterTestCase.php',
'ArcanistPyLintLinter' => 'lint/linter/ArcanistPyLintLinter.php',
'ArcanistPyLintLinterTestCase' => 'lint/linter/__tests__/ArcanistPyLintLinterTestCase.php',
'ArcanistRaggedClassTreeEdgeXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistRaggedClassTreeEdgeXHPASTLinterRule.php',
'ArcanistRaggedClassTreeEdgeXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistRaggedClassTreeEdgeXHPASTLinterRuleTestCase.php',
'ArcanistRef' => 'ref/ArcanistRef.php',
@ -412,13 +371,8 @@ phutil_register_library_map(array(
'ArcanistRevertWorkflow' => 'workflow/ArcanistRevertWorkflow.php',
'ArcanistRevisionRef' => 'ref/ArcanistRevisionRef.php',
'ArcanistRevisionRefSource' => 'ref/ArcanistRevisionRefSource.php',
'ArcanistRuboCopLinter' => 'lint/linter/ArcanistRuboCopLinter.php',
'ArcanistRuboCopLinterTestCase' => 'lint/linter/__tests__/ArcanistRuboCopLinterTestCase.php',
'ArcanistRubyLinter' => 'lint/linter/ArcanistRubyLinter.php',
'ArcanistRubyLinterTestCase' => 'lint/linter/__tests__/ArcanistRubyLinterTestCase.php',
'ArcanistRuntimeConfigurationSource' => 'config/source/ArcanistRuntimeConfigurationSource.php',
'ArcanistScalarConfigOption' => 'config/option/ArcanistScalarConfigOption.php',
'ArcanistScriptAndRegexLinter' => 'lint/linter/ArcanistScriptAndRegexLinter.php',
'ArcanistSelfClassReferenceXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistSelfClassReferenceXHPASTLinterRule.php',
'ArcanistSelfClassReferenceXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistSelfClassReferenceXHPASTLinterRuleTestCase.php',
'ArcanistSelfMemberReferenceXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistSelfMemberReferenceXHPASTLinterRule.php',
@ -516,8 +470,6 @@ phutil_register_library_map(array(
'ArcanistXHPASTLinterRule' => 'lint/linter/xhpast/ArcanistXHPASTLinterRule.php',
'ArcanistXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistXHPASTLinterRuleTestCase.php',
'ArcanistXHPASTLinterTestCase' => 'lint/linter/__tests__/ArcanistXHPASTLinterTestCase.php',
'ArcanistXMLLinter' => 'lint/linter/ArcanistXMLLinter.php',
'ArcanistXMLLinterTestCase' => 'lint/linter/__tests__/ArcanistXMLLinterTestCase.php',
'ArcanistXUnitTestResultParser' => 'unit/parser/ArcanistXUnitTestResultParser.php',
'BaseHTTPFuture' => 'future/http/BaseHTTPFuture.php',
'CaseInsensitiveArray' => 'utils/CaseInsensitiveArray.php',
@ -1201,9 +1153,6 @@ phutil_register_library_map(array(
'ArcanistBuildRef' => 'Phobject',
'ArcanistBundle' => 'Phobject',
'ArcanistBundleTestCase' => 'PhutilTestCase',
'ArcanistCSSLintLinter' => 'ArcanistExternalLinter',
'ArcanistCSSLintLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistCSharpLinter' => 'ArcanistLinter',
'ArcanistCallConduitWorkflow' => 'ArcanistWorkflow',
'ArcanistCallParenthesesXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistCallParenthesesXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
@ -1224,10 +1173,6 @@ phutil_register_library_map(array(
'ArcanistClassNameLiteralXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistCloseRevisionWorkflow' => 'ArcanistWorkflow',
'ArcanistCloseWorkflow' => 'ArcanistWorkflow',
'ArcanistClosureLinter' => 'ArcanistExternalLinter',
'ArcanistClosureLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistCoffeeLintLinter' => 'ArcanistExternalLinter',
'ArcanistCoffeeLintLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistCommentRemover' => 'Phobject',
'ArcanistCommentRemoverTestCase' => 'PhutilTestCase',
'ArcanistCommentSpacingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
@ -1237,7 +1182,6 @@ phutil_register_library_map(array(
'ArcanistCommitUpstreamHardpointLoader' => 'ArcanistHardpointLoader',
'ArcanistCommitWorkflow' => 'ArcanistWorkflow',
'ArcanistCompilerLintRenderer' => 'ArcanistLintRenderer',
'ArcanistComposerLinter' => 'ArcanistLinter',
'ArcanistComprehensiveLintEngine' => 'ArcanistLintEngine',
'ArcanistConcatenationOperatorXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistConcatenationOperatorXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
@ -1259,10 +1203,6 @@ phutil_register_library_map(array(
'ArcanistControlStatementSpacingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistControlStatementSpacingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistCoverWorkflow' => 'ArcanistWorkflow',
'ArcanistCppcheckLinter' => 'ArcanistExternalLinter',
'ArcanistCppcheckLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistCpplintLinter' => 'ArcanistExternalLinter',
'ArcanistCpplintLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistCurlyBraceArrayIndexXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistCurlyBraceArrayIndexXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistDeclarationParenthesesXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
@ -1306,8 +1246,6 @@ phutil_register_library_map(array(
'ArcanistExitExpressionXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistExitExpressionXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistExportWorkflow' => 'ArcanistWorkflow',
'ArcanistExternalLinter' => 'ArcanistFutureLinter',
'ArcanistExternalLinterTestCase' => 'ArcanistLinterTestCase',
'ArcanistExtractUseXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistExtractUseXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistFeatureWorkflow' => 'ArcanistWorkflow',
@ -1318,13 +1256,10 @@ phutil_register_library_map(array(
'ArcanistFilenameLinterTestCase' => 'ArcanistLinterTestCase',
'ArcanistFilesystemConfigurationSource' => 'ArcanistDictionaryConfigurationSource',
'ArcanistFlagWorkflow' => 'ArcanistWorkflow',
'ArcanistFlake8Linter' => 'ArcanistExternalLinter',
'ArcanistFlake8LinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistFormattedStringXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistFormattedStringXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistFunctionCallShouldBeTypeCastXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistFunctionCallShouldBeTypeCastXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistFutureLinter' => 'ArcanistLinter',
'ArcanistGeneratedLinter' => 'ArcanistLinter',
'ArcanistGeneratedLinterTestCase' => 'ArcanistLinterTestCase',
'ArcanistGetConfigWorkflow' => 'ArcanistWorkflow',
@ -1337,12 +1272,8 @@ phutil_register_library_map(array(
'ArcanistGitWorkingCopy' => 'ArcanistWorkingCopy',
'ArcanistGlobalVariableXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistGlobalVariableXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistGoLintLinter' => 'ArcanistExternalLinter',
'ArcanistGoLintLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistGoTestResultParser' => 'ArcanistTestResultParser',
'ArcanistGoTestResultParserTestCase' => 'PhutilTestCase',
'ArcanistHLintLinter' => 'ArcanistExternalLinter',
'ArcanistHLintLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistHardpointLoader' => 'Phobject',
'ArcanistHelpWorkflow' => 'ArcanistWorkflow',
'ArcanistHexadecimalNumericScalarCasingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
@ -1376,16 +1307,10 @@ phutil_register_library_map(array(
'ArcanistInvalidOctalNumericScalarXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistIsAShouldBeInstanceOfXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistIsAShouldBeInstanceOfXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistJSHintLinter' => 'ArcanistExternalLinter',
'ArcanistJSHintLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistJSONLintLinter' => 'ArcanistExternalLinter',
'ArcanistJSONLintLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistJSONLintRenderer' => 'ArcanistLintRenderer',
'ArcanistJSONLinter' => 'ArcanistLinter',
'ArcanistJSONLinterTestCase' => 'ArcanistLinterTestCase',
'ArcanistJSONUnitSink' => 'ArcanistUnitSink',
'ArcanistJscsLinter' => 'ArcanistExternalLinter',
'ArcanistJscsLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistKeywordCasingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistKeywordCasingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistLambdaFuncFunctionXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
@ -1394,8 +1319,6 @@ phutil_register_library_map(array(
'ArcanistLandWorkflow' => 'ArcanistWorkflow',
'ArcanistLanguageConstructParenthesesXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistLanguageConstructParenthesesXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistLesscLinter' => 'ArcanistExternalLinter',
'ArcanistLesscLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistLiberateWorkflow' => 'ArcanistWorkflow',
'ArcanistLintEngine' => 'Phobject',
'ArcanistLintMessage' => 'Phobject',
@ -1452,8 +1375,6 @@ phutil_register_library_map(array(
'ArcanistNoneLintRenderer' => 'ArcanistLintRenderer',
'ArcanistObjectOperatorSpacingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistObjectOperatorSpacingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistPEP8Linter' => 'ArcanistExternalLinter',
'ArcanistPEP8LinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistPHPCloseTagXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistPHPCloseTagXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistPHPCompatibilityXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
@ -1475,10 +1396,6 @@ phutil_register_library_map(array(
'ArcanistPasteWorkflow' => 'ArcanistWorkflow',
'ArcanistPatchWorkflow' => 'ArcanistWorkflow',
'ArcanistPhageToolset' => 'ArcanistToolset',
'ArcanistPhpLinter' => 'ArcanistExternalLinter',
'ArcanistPhpLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistPhpcsLinter' => 'ArcanistExternalLinter',
'ArcanistPhpcsLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistPhpunitTestResultParser' => 'ArcanistTestResultParser',
'ArcanistPhrequentWorkflow' => 'ArcanistWorkflow',
'ArcanistPhutilLibraryLinter' => 'ArcanistLinter',
@ -1493,12 +1410,6 @@ phutil_register_library_map(array(
'ArcanistPromptsWorkflow' => 'ArcanistWorkflow',
'ArcanistPublicPropertyXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistPublicPropertyXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistPuppetLintLinter' => 'ArcanistExternalLinter',
'ArcanistPuppetLintLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistPyFlakesLinter' => 'ArcanistExternalLinter',
'ArcanistPyFlakesLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistPyLintLinter' => 'ArcanistExternalLinter',
'ArcanistPyLintLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistRaggedClassTreeEdgeXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistRaggedClassTreeEdgeXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistRef' => 'Phobject',
@ -1516,13 +1427,8 @@ phutil_register_library_map(array(
'ArcanistRevertWorkflow' => 'ArcanistWorkflow',
'ArcanistRevisionRef' => 'ArcanistRef',
'ArcanistRevisionRefSource' => 'Phobject',
'ArcanistRuboCopLinter' => 'ArcanistExternalLinter',
'ArcanistRuboCopLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistRubyLinter' => 'ArcanistExternalLinter',
'ArcanistRubyLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistRuntimeConfigurationSource' => 'ArcanistDictionaryConfigurationSource',
'ArcanistScalarConfigOption' => 'ArcanistConfigOption',
'ArcanistScriptAndRegexLinter' => 'ArcanistLinter',
'ArcanistSelfClassReferenceXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistSelfClassReferenceXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistSelfMemberReferenceXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
@ -1620,8 +1526,6 @@ phutil_register_library_map(array(
'ArcanistXHPASTLinterRule' => 'Phobject',
'ArcanistXHPASTLinterRuleTestCase' => 'ArcanistLinterTestCase',
'ArcanistXHPASTLinterTestCase' => 'ArcanistLinterTestCase',
'ArcanistXMLLinter' => 'ArcanistLinter',
'ArcanistXMLLinterTestCase' => 'ArcanistLinterTestCase',
'ArcanistXUnitTestResultParser' => 'Phobject',
'BaseHTTPFuture' => 'Future',
'CaseInsensitiveArray' => 'PhutilArray',

View file

@ -1,127 +0,0 @@
<?php
/**
* Uses "CSS Lint" to detect checkstyle errors in CSS code.
*/
final class ArcanistCSSLintLinter extends ArcanistExternalLinter {
public function getInfoName() {
return 'CSSLint';
}
public function getInfoURI() {
return 'http://csslint.net';
}
public function getInfoDescription() {
return pht(
'Use `%s` to detect issues with CSS source files.',
'csslint');
}
public function getLinterName() {
return 'CSSLint';
}
public function getLinterConfigurationName() {
return 'csslint';
}
protected function getMandatoryFlags() {
return array(
'--format=lint-xml',
);
}
public function getDefaultBinary() {
return 'csslint';
}
public function getVersion() {
list($stdout) = execx('%C --version', $this->getExecutableCommand());
$matches = array();
if (preg_match('/^v(?P<version>\d+\.\d+\.\d+)$/', $stdout, $matches)) {
return $matches['version'];
} else {
return false;
}
}
public function getInstallInstructions() {
return pht(
'Install %s using `%s`.', 'CSSLint',
'npm install -g csslint');
}
protected function parseLinterOutput($path, $err, $stdout, $stderr) {
$report_dom = new DOMDocument();
$ok = @$report_dom->loadXML($stdout);
if (!$ok) {
return false;
}
$files = $report_dom->getElementsByTagName('file');
$messages = array();
foreach ($files as $file) {
foreach ($file->childNodes as $child) {
$line = $child->getAttribute('line');
$char = $child->getAttribute('char');
$original_text = $child->getAttribute('evidence');
if ($line === '') {
$line = null;
}
if ($char === '') {
$char = null;
} else {
$original_text = substr($original_text, $char - 1);
}
$message = id(new ArcanistLintMessage())
->setPath($path)
->setLine($line)
->setChar($char)
->setCode($this->getLinterName())
->setName($this->getLinterName())
->setDescription($child->getAttribute('reason'))
->setOriginalText($original_text);
switch ($child->getAttribute('severity')) {
case 'error':
$message->setSeverity(ArcanistLintSeverity::SEVERITY_ERROR);
break;
case 'warning':
$message->setSeverity(ArcanistLintSeverity::SEVERITY_WARNING);
break;
default:
$message->setSeverity(ArcanistLintSeverity::SEVERITY_ERROR);
break;
}
$messages[] = $message;
}
}
return $messages;
}
protected function getLintCodeFromLinterConfigurationKey($code) {
// NOTE: We can't figure out which rule generated each message, so we
// can not customize severities. I opened a pull request to add this
// ability; see:
//
// https://github.com/stubbornella/csslint/pull/409
throw new Exception(
pht(
"%s does not currently support custom severity levels, because ".
"rules can't be identified from messages in output.",
'CSSLint'));
}
}

View file

@ -1,261 +0,0 @@
<?php
/**
* C# linter for Arcanist.
*/
final class ArcanistCSharpLinter extends ArcanistLinter {
private $runtimeEngine;
private $cslintEngine;
private $cslintHintPath;
private $loaded;
private $discoveryMap;
private $futures;
const SUPPORTED_VERSION = 1;
public function getLinterName() {
return 'C#';
}
public function getLinterConfigurationName() {
return 'csharp';
}
public function getLinterConfigurationOptions() {
$options = parent::getLinterConfigurationOptions();
$options['discovery'] = array(
'type' => 'map<string, list<string>>',
'help' => pht('Provide a discovery map.'),
);
// TODO: This should probably be replaced with "bin" when this moves
// to extend ExternalLinter.
$options['binary'] = array(
'type' => 'string',
'help' => pht('Override default binary.'),
);
return $options;
}
public function setLinterConfigurationValue($key, $value) {
switch ($key) {
case 'discovery':
$this->discoveryMap = $value;
return;
case 'binary':
$this->cslintHintPath = $value;
return;
}
parent::setLinterConfigurationValue($key, $value);
}
protected function getLintCodeFromLinterConfigurationKey($code) {
return $code;
}
public function setCustomSeverityMap(array $map) {
foreach ($map as $code => $severity) {
if (substr($code, 0, 2) === 'SA' && $severity == 'disabled') {
throw new Exception(
pht(
"In order to keep StyleCop integration with IDEs and other tools ".
"consistent with Arcanist results, you aren't permitted to ".
"disable StyleCop rules within '%s'. Instead configure the ".
"severity using the StyleCop settings dialog (usually accessible ".
"from within your IDE). StyleCop settings for your project will ".
"be used when linting for Arcanist.",
'.arclint'));
}
}
return parent::setCustomSeverityMap($map);
}
/**
* Determines what executables and lint paths to use. Between platforms
* this also changes whether the lint engine is run under .NET or Mono. It
* also ensures that all of the required binaries are available for the lint
* to run successfully.
*
* @return void
*/
private function loadEnvironment() {
if ($this->loaded) {
return;
}
// Determine runtime engine (.NET or Mono).
if (phutil_is_windows()) {
$this->runtimeEngine = '';
} else if (Filesystem::binaryExists('mono')) {
$this->runtimeEngine = 'mono ';
} else {
throw new Exception(
pht('Unable to find Mono and you are not on Windows!'));
}
// Determine cslint path.
$cslint = $this->cslintHintPath;
if ($cslint !== null && file_exists($cslint)) {
$this->cslintEngine = Filesystem::resolvePath($cslint);
} else if (Filesystem::binaryExists('cslint.exe')) {
$this->cslintEngine = 'cslint.exe';
} else {
throw new Exception(pht('Unable to locate %s.', 'cslint'));
}
// Determine cslint version.
$ver_future = new ExecFuture(
'%C -v',
$this->runtimeEngine.$this->cslintEngine);
list($err, $stdout, $stderr) = $ver_future->resolve();
if ($err !== 0) {
throw new Exception(
pht(
'You are running an old version of %s. Please '.
'upgrade to version %s.',
'cslint',
self::SUPPORTED_VERSION));
}
$ver = (int)$stdout;
if ($ver < self::SUPPORTED_VERSION) {
throw new Exception(
pht(
'You are running an old version of %s. Please '.
'upgrade to version %s.',
'cslint',
self::SUPPORTED_VERSION));
} else if ($ver > self::SUPPORTED_VERSION) {
throw new Exception(
pht(
'Arcanist does not support this version of %s (it is newer). '.
'You can try upgrading Arcanist with `%s`.',
'cslint',
'arc upgrade'));
}
$this->loaded = true;
}
public function lintPath($path) {}
public function willLintPaths(array $paths) {
$this->loadEnvironment();
$futures = array();
// Bulk linting up into futures, where the number of files
// is based on how long the command is.
$current_paths = array();
foreach ($paths as $path) {
// If the current paths for the command, plus the next path
// is greater than 6000 characters (less than the Windows
// command line limit), then finalize this future and add it.
$total = 0;
foreach ($current_paths as $current_path) {
$total += strlen($current_path) + 3; // Quotes and space.
}
if ($total + strlen($path) > 6000) {
// %s won't pass through the JSON correctly
// under Windows. This is probably because not only
// does the JSON have quotation marks in the content,
// but because there'll be a lot of escaping and
// double escaping because the JSON also contains
// regular expressions. cslint supports passing the
// settings JSON through base64-encoded to mitigate
// this issue.
$futures[] = new ExecFuture(
'%C --settings-base64=%s -r=. %Ls',
$this->runtimeEngine.$this->cslintEngine,
base64_encode(json_encode($this->discoveryMap)),
$current_paths);
$current_paths = array();
}
// Append the path to the current paths array.
$current_paths[] = $this->getEngine()->getFilePathOnDisk($path);
}
// If we still have paths left in current paths, then we need to create
// a future for those too.
if (count($current_paths) > 0) {
$futures[] = new ExecFuture(
'%C --settings-base64=%s -r=. %Ls',
$this->runtimeEngine.$this->cslintEngine,
base64_encode(json_encode($this->discoveryMap)),
$current_paths);
$current_paths = array();
}
$this->futures = $futures;
}
public function didLintPaths(array $paths) {
if ($this->futures) {
$futures = id(new FutureIterator($this->futures))
->limit(8);
foreach ($futures as $future) {
$this->resolveFuture($future);
}
$this->futures = array();
}
}
protected function resolveFuture(Future $future) {
list($stdout) = $future->resolvex();
$all_results = json_decode($stdout);
foreach ($all_results as $results) {
if ($results === null || $results->Issues === null) {
return;
}
foreach ($results->Issues as $issue) {
$message = new ArcanistLintMessage();
$message->setPath($results->FileName);
$message->setLine($issue->LineNumber);
$message->setCode($issue->Index->Code);
$message->setName($issue->Index->Name);
$message->setChar($issue->Column);
$message->setOriginalText($issue->OriginalText);
$message->setReplacementText($issue->ReplacementText);
$desc = @vsprintf($issue->Index->Message, $issue->Parameters);
if ($desc === false) {
$desc = $issue->Index->Message;
}
$message->setDescription($desc);
$severity = ArcanistLintSeverity::SEVERITY_ADVICE;
switch ($issue->Index->Severity) {
case 0:
$severity = ArcanistLintSeverity::SEVERITY_ADVICE;
break;
case 1:
$severity = ArcanistLintSeverity::SEVERITY_AUTOFIX;
break;
case 2:
$severity = ArcanistLintSeverity::SEVERITY_WARNING;
break;
case 3:
$severity = ArcanistLintSeverity::SEVERITY_ERROR;
break;
case 4:
$severity = ArcanistLintSeverity::SEVERITY_DISABLED;
break;
}
$severity_override = $this->getLintMessageSeverity($issue->Index->Code);
if ($severity_override !== null) {
$severity = $severity_override;
}
$message->setSeverity($severity);
$this->addLintMessage($message);
}
}
}
protected function getDefaultMessageSeverity($code) {
return null;
}
}

View file

@ -1,62 +0,0 @@
<?php
/**
* Uses `gjslint` to detect errors and potential problems in JavaScript code.
*/
final class ArcanistClosureLinter extends ArcanistExternalLinter {
public function getInfoName() {
return pht('Closure Linter');
}
public function getInfoURI() {
return 'https://developers.google.com/closure/utilities/';
}
public function getInfoDescription() {
return pht("Uses Google's Closure Linter to check JavaScript code.");
}
public function getLinterName() {
return 'GJSLINT';
}
public function getLinterConfigurationName() {
return 'gjslint';
}
public function getDefaultBinary() {
return 'gjslint';
}
public function getInstallInstructions() {
return pht(
'Install %s using `%s`.',
'gjslint',
'pip install closure-linter');
}
protected function parseLinterOutput($path, $err, $stdout, $stderr) {
$lines = phutil_split_lines($stdout, false);
$messages = array();
foreach ($lines as $line) {
$matches = null;
if (!preg_match('/^Line (\d+), E:(\d+): (.*)/', $line, $matches)) {
continue;
}
$message = id(new ArcanistLintMessage())
->setPath($path)
->setLine($matches[1])
->setName('GJSLINT'.$matches[2])
->setSeverity(ArcanistLintSeverity::SEVERITY_ERROR)
->setCode($this->getLinterName().$matches[2])
->setDescription($matches[3]);
$messages[] = $message;
}
return $messages;
}
}

View file

@ -1,135 +0,0 @@
<?php
final class ArcanistCoffeeLintLinter extends ArcanistExternalLinter {
private $config;
public function getInfoName() {
return 'CoffeeLint';
}
public function getInfoURI() {
return 'http://www.coffeelint.org';
}
public function getInfoDescription() {
return pht(
'CoffeeLint is a style checker that helps keep CoffeeScript '.
'code clean and consistent.');
}
public function getLinterName() {
return 'COFFEE';
}
public function getLinterConfigurationName() {
return 'coffeelint';
}
public function getDefaultBinary() {
return 'coffeelint';
}
public function getVersion() {
list($stdout) = execx('%C --version', $this->getExecutableCommand());
$matches = array();
if (preg_match('/^(?P<version>\d+\.\d+\.\d+)$/', $stdout, $matches)) {
return $matches['version'];
} else {
return false;
}
}
public function getInstallInstructions() {
return pht(
'Install CoffeeLint using `%s`.',
'npm install -g coffeelint');
}
protected function getMandatoryFlags() {
$options = array(
'--reporter=raw',
);
if ($this->config) {
$options[] = '--file='.$this->config;
}
return $options;
}
public function getLinterConfigurationOptions() {
$options = array(
'coffeelint.config' => array(
'type' => 'optional string',
'help' => pht('A custom configuration file.'),
),
);
return $options + parent::getLinterConfigurationOptions();
}
public function setLinterConfigurationValue($key, $value) {
switch ($key) {
case 'coffeelint.config':
$this->config = $value;
return;
}
return parent::setLinterConfigurationValue($key, $value);
}
protected function parseLinterOutput($path, $err, $stdout, $stderr) {
$messages = array();
$output = phutil_json_decode($stdout);
// We are only linting a single file.
if (count($output) != 1) {
return false;
}
foreach ($output as $reports) {
foreach ($reports as $report) {
// Column number is not provided in the output.
// See https://github.com/clutchski/coffeelint/issues/87
$message = id(new ArcanistLintMessage())
->setPath($path)
->setLine($report['lineNumber'])
->setCode($this->getLinterName())
->setName(ucwords(str_replace('_', ' ', $report['name'])))
->setDescription($report['message'])
->setOriginalText(idx($report, 'line'));
switch ($report['level']) {
case 'warn':
$message->setSeverity(ArcanistLintSeverity::SEVERITY_WARNING);
break;
case 'error':
$message->setSeverity(ArcanistLintSeverity::SEVERITY_ERROR);
break;
default:
$message->setSeverity(ArcanistLintSeverity::SEVERITY_ADVICE);
break;
}
$messages[] = $message;
}
}
return $messages;
}
protected function getLintCodeFromLinterConfigurationKey($code) {
// NOTE: We can't figure out which rule generated each message, so we
// can not customize severities.
throw new Exception(
pht(
"CoffeeLint does not currently support custom severity levels, ".
"because rules can't be identified from messages in output."));
}
}

View file

@ -1,55 +0,0 @@
<?php
final class ArcanistComposerLinter extends ArcanistLinter {
const LINT_OUT_OF_DATE = 1;
public function getInfoName() {
return pht('Composer Dependency Manager');
}
public function getInfoDescription() {
return pht('A linter for Composer related files.');
}
public function getLinterName() {
return 'COMPOSER';
}
public function getLinterConfigurationName() {
return 'composer';
}
public function getLintNameMap() {
return array(
self::LINT_OUT_OF_DATE => pht('Lock file out-of-date'),
);
}
public function lintPath($path) {
switch (basename($path)) {
case 'composer.json':
$this->lintComposerJson($path);
break;
case 'composer.lock':
break;
}
}
private function lintComposerJson($path) {
$composer_hash = md5(Filesystem::readFile(dirname($path).'/composer.json'));
$composer_lock = phutil_json_decode(
Filesystem::readFile(dirname($path).'/composer.lock'));
if ($composer_hash !== $composer_lock['hash']) {
$this->raiseLintAtPath(
self::LINT_OUT_OF_DATE,
pht(
"The '%s' file seems to be out-of-date. ".
"You probably need to run `%s`.",
'composer.lock',
'composer update'));
}
}
}

View file

@ -1,112 +0,0 @@
<?php
/**
* Uses Cppcheck to do basic checks in a C++ file.
*/
final class ArcanistCppcheckLinter extends ArcanistExternalLinter {
public function getInfoName() {
return 'C++ linter';
}
public function getInfoURI() {
return 'http://cppcheck.sourceforge.net';
}
public function getInfoDescription() {
return pht(
'Use `%s` to perform static analysis on C/C++ code.',
'cppcheck');
}
public function getLinterName() {
return 'cppcheck';
}
public function getLinterConfigurationName() {
return 'cppcheck';
}
public function getDefaultBinary() {
return 'cppcheck';
}
public function getVersion() {
list($stdout) = execx('%C --version', $this->getExecutableCommand());
$matches = array();
$regex = '/^Cppcheck (?P<version>\d+\.\d+)$/';
if (preg_match($regex, $stdout, $matches)) {
return $matches['version'];
} else {
return false;
}
}
public function getInstallInstructions() {
return pht(
'Install Cppcheck using `%s` or similar.',
'apt-get install cppcheck');
}
protected function getDefaultFlags() {
return array(
'-j2',
'--enable=performance,style,portability,information',
);
}
protected function getMandatoryFlags() {
return array(
'--quiet',
'--inline-suppr',
'--xml',
'--xml-version=2',
);
}
public function shouldExpectCommandErrors() {
return false;
}
protected function parseLinterOutput($path, $err, $stdout, $stderr) {
$dom = new DOMDocument();
$ok = @$dom->loadXML($stderr);
if (!$ok) {
return false;
}
$errors = $dom->getElementsByTagName('error');
$messages = array();
foreach ($errors as $error) {
foreach ($error->getElementsByTagName('location') as $location) {
$message = new ArcanistLintMessage();
$message->setPath($location->getAttribute('file'));
$message->setLine($location->getAttribute('line'));
$message->setCode('Cppcheck');
$message->setName($error->getAttribute('id'));
$message->setDescription($error->getAttribute('msg'));
switch ($error->getAttribute('severity')) {
case 'error':
$message->setSeverity(ArcanistLintSeverity::SEVERITY_ERROR);
break;
default:
if ($error->getAttribute('inconclusive')) {
$message->setSeverity(ArcanistLintSeverity::SEVERITY_ADVICE);
} else {
$message->setSeverity(ArcanistLintSeverity::SEVERITY_WARNING);
}
break;
}
$messages[] = $message;
}
}
return $messages;
}
}

View file

@ -1,77 +0,0 @@
<?php
/**
* Uses Google's `cpplint.py` to check code.
*/
final class ArcanistCpplintLinter extends ArcanistExternalLinter {
public function getLinterName() {
return 'C++ Google\'s Styleguide';
}
public function getLinterConfigurationName() {
return 'cpplint';
}
public function getDefaultBinary() {
return 'cpplint.py';
}
public function getInstallInstructions() {
return pht(
'Install cpplint.py using `%s`, and place it in your path with the '.
'appropriate permissions set.',
'wget https://raw.github.com'.
'/google/styleguide/gh-pages/cpplint/cpplint.py');
}
protected function getDefaultMessageSeverity($code) {
return ArcanistLintSeverity::SEVERITY_WARNING;
}
protected function parseLinterOutput($path, $err, $stdout, $stderr) {
$lines = explode("\n", $stderr);
$messages = array();
foreach ($lines as $line) {
$line = trim($line);
$matches = null;
$regex = '/(\d+):\s*(.*)\s*\[(.*)\] \[(\d+)\]$/';
if (!preg_match($regex, $line, $matches)) {
continue;
}
foreach ($matches as $key => $match) {
$matches[$key] = trim($match);
}
$severity = $this->getLintMessageSeverity($matches[3]);
$message = new ArcanistLintMessage();
$message->setPath($path);
$message->setLine($matches[1]);
$message->setCode($matches[3]);
$message->setName($matches[3]);
$message->setDescription($matches[2]);
$message->setSeverity($severity);
$messages[] = $message;
}
return $messages;
}
protected function getLintCodeFromLinterConfigurationKey($code) {
if (!preg_match('@^[a-z_]+/[a-z0-9_+]+$@', $code)) {
throw new Exception(
pht(
'Unrecognized lint message code "%s". Expected a valid cpplint '.
'lint code like "%s" or "%s".',
$code,
'build/include_order',
'whitespace/braces'));
}
return $code;
}
}

View file

@ -1,570 +0,0 @@
<?php
/**
* Base class for linters which operate by invoking an external program and
* parsing results.
*
* @task bin Interpreters, Binaries and Flags
* @task parse Parsing Linter Output
* @task exec Executing the Linter
*/
abstract class ArcanistExternalLinter extends ArcanistFutureLinter {
private $bin;
private $interpreter;
private $flags;
private $versionRequirement;
/* -( Interpreters, Binaries and Flags )----------------------------------- */
/**
* Return the default binary name or binary path where the external linter
* lives. This can either be a binary name which is expected to be installed
* in PATH (like "jshint"), or a relative path from the project root
* (like "resources/support/bin/linter") or an absolute path.
*
* If the binary needs an interpreter (like "python" or "node"), you should
* also override @{method:shouldUseInterpreter} and provide the interpreter
* in @{method:getDefaultInterpreter}.
*
* @return string Default binary to execute.
* @task bin
*/
abstract public function getDefaultBinary();
/**
* Return a human-readable string describing how to install the linter. This
* is normally something like "Install such-and-such by running `npm install
* -g such-and-such`.", but will differ from linter to linter.
*
* @return string Human readable install instructions
* @task bin
*/
abstract public function getInstallInstructions();
/**
* Return a human-readable string describing how to upgrade the linter.
*
* @return string Human readable upgrade instructions
* @task bin
*/
public function getUpgradeInstructions() {
return null;
}
/**
* Return true to continue when the external linter exits with an error code.
* By default, linters which exit with an error code are assumed to have
* failed. However, some linters exit with a specific code to indicate that
* lint messages were detected.
*
* If the linter sometimes raises errors during normal operation, override
* this method and return true so execution continues when it exits with
* a nonzero status.
*
* @param bool Return true to continue on nonzero error code.
* @task bin
*/
public function shouldExpectCommandErrors() {
return true;
}
/**
* Provide mandatory, non-overridable flags to the linter. Generally these
* are format flags, like `--format=xml`, which must always be given for
* the output to be usable.
*
* Flags which are not mandatory should be provided in
* @{method:getDefaultFlags} instead.
*
* @return list<string> Mandatory flags, like `"--format=xml"`.
* @task bin
*/
protected function getMandatoryFlags() {
return array();
}
/**
* Provide default, overridable flags to the linter. Generally these are
* configuration flags which affect behavior but aren't critical. Flags
* which are required should be provided in @{method:getMandatoryFlags}
* instead.
*
* Default flags can be overridden with @{method:setFlags}.
*
* @return list<string> Overridable default flags.
* @task bin
*/
protected function getDefaultFlags() {
return array();
}
/**
* Override default flags with custom flags. If not overridden, flags provided
* by @{method:getDefaultFlags} are used.
*
* @param list<string> New flags.
* @return this
* @task bin
*/
final public function setFlags(array $flags) {
$this->flags = $flags;
return $this;
}
/**
* Set the binary's version requirement.
*
* @param string Version requirement.
* @return this
* @task bin
*/
final public function setVersionRequirement($version) {
$this->versionRequirement = trim($version);
return $this;
}
/**
* Return the binary or script to execute. This method synthesizes defaults
* and configuration. You can override the binary with @{method:setBinary}.
*
* @return string Binary to execute.
* @task bin
*/
final public function getBinary() {
return coalesce($this->bin, $this->getDefaultBinary());
}
/**
* Override the default binary with a new one.
*
* @param string New binary.
* @return this
* @task bin
*/
final public function setBinary($bin) {
$this->bin = $bin;
return $this;
}
/**
* Return true if this linter should use an interpreter (like "python" or
* "node") in addition to the script.
*
* After overriding this method to return `true`, override
* @{method:getDefaultInterpreter} to set a default.
*
* @return bool True to use an interpreter.
* @task bin
*/
public function shouldUseInterpreter() {
return false;
}
/**
* Return the default interpreter, like "python" or "node". This method is
* only invoked if @{method:shouldUseInterpreter} has been overridden to
* return `true`.
*
* @return string Default interpreter.
* @task bin
*/
public function getDefaultInterpreter() {
throw new PhutilMethodNotImplementedException();
}
/**
* Get the effective interpreter. This method synthesizes configuration and
* defaults.
*
* @return string Effective interpreter.
* @task bin
*/
final public function getInterpreter() {
return coalesce($this->interpreter, $this->getDefaultInterpreter());
}
/**
* Set the interpreter, overriding any default.
*
* @param string New interpreter.
* @return this
* @task bin
*/
final public function setInterpreter($interpreter) {
$this->interpreter = $interpreter;
return $this;
}
/* -( Parsing Linter Output )---------------------------------------------- */
/**
* Parse the output of the external lint program into objects of class
* @{class:ArcanistLintMessage} which `arc` can consume. Generally, this
* means examining the output and converting each warning or error into a
* message.
*
* If parsing fails, returning `false` will cause the caller to throw an
* appropriate exception. (You can also throw a more specific exception if
* you're able to detect a more specific condition.) Otherwise, return a list
* of messages.
*
* @param string Path to the file being linted.
* @param int Exit code of the linter.
* @param string Stdout of the linter.
* @param string Stderr of the linter.
* @return list<ArcanistLintMessage>|false List of lint messages, or false
* to indicate parser failure.
* @task parse
*/
abstract protected function parseLinterOutput($path, $err, $stdout, $stderr);
/* -( Executing the Linter )----------------------------------------------- */
/**
* Check that the binary and interpreter (if applicable) exist, and throw
* an exception with a message about how to install them if they do not.
*
* @return void
*/
final public function checkBinaryConfiguration() {
$interpreter = null;
if ($this->shouldUseInterpreter()) {
$interpreter = $this->getInterpreter();
}
$binary = $this->getBinary();
// NOTE: If we have an interpreter, we don't require the script to be
// executable (so we just check that the path exists). Otherwise, the
// binary must be executable.
if ($interpreter) {
if (!Filesystem::binaryExists($interpreter)) {
throw new ArcanistMissingLinterException(
pht(
'Unable to locate interpreter "%s" to run linter %s. You may need '.
'to install the interpreter, or adjust your linter configuration.',
$interpreter,
get_class($this)));
}
if (!Filesystem::pathExists($binary)) {
throw new ArcanistMissingLinterException(
sprintf(
"%s\n%s",
pht(
'Unable to locate script "%s" to run linter %s. You may need '.
'to install the script, or adjust your linter configuration.',
$binary,
get_class($this)),
pht(
'TO INSTALL: %s',
$this->getInstallInstructions())));
}
} else {
if (!Filesystem::binaryExists($binary)) {
throw new ArcanistMissingLinterException(
sprintf(
"%s\n%s",
pht(
'Unable to locate binary "%s" to run linter %s. You may need '.
'to install the binary, or adjust your linter configuration.',
$binary,
get_class($this)),
pht(
'TO INSTALL: %s',
$this->getInstallInstructions())));
}
}
}
/**
* If a binary version requirement has been specified, compare the version
* of the configured binary to the required version, and if the binary's
* version is not supported, throw an exception.
*
* @param string Version string to check.
* @return void
*/
final protected function checkBinaryVersion($version) {
if (!$this->versionRequirement) {
return;
}
if (!$version) {
$message = pht(
'Linter %s requires %s version %s. Unable to determine the version '.
'that you have installed.',
get_class($this),
$this->getBinary(),
$this->versionRequirement);
$instructions = $this->getUpgradeInstructions();
if ($instructions) {
$message .= "\n".pht('TO UPGRADE: %s', $instructions);
}
throw new ArcanistMissingLinterException($message);
}
$operator = '==';
$compare_to = $this->versionRequirement;
$matches = null;
if (preg_match('/^([<>]=?|=)\s*(.*)$/', $compare_to, $matches)) {
$operator = $matches[1];
$compare_to = $matches[2];
if ($operator === '=') {
$operator = '==';
}
}
if (!version_compare($version, $compare_to, $operator)) {
$message = pht(
'Linter %s requires %s version %s. You have version %s.',
get_class($this),
$this->getBinary(),
$this->versionRequirement,
$version);
$instructions = $this->getUpgradeInstructions();
if ($instructions) {
$message .= "\n".pht('TO UPGRADE: %s', $instructions);
}
throw new ArcanistMissingLinterException($message);
}
}
/**
* Get the composed executable command, including the interpreter and binary
* but without flags or paths. This can be used to execute `--version`
* commands.
*
* @return string Command to execute the raw linter.
* @task exec
*/
final protected function getExecutableCommand() {
$this->checkBinaryConfiguration();
$interpreter = null;
if ($this->shouldUseInterpreter()) {
$interpreter = $this->getInterpreter();
}
$binary = $this->getBinary();
if ($interpreter) {
$bin = csprintf('%s %s', $interpreter, $binary);
} else {
$bin = csprintf('%s', $binary);
}
return $bin;
}
/**
* Get the composed flags for the executable, including both mandatory and
* configured flags.
*
* @return list<string> Composed flags.
* @task exec
*/
final protected function getCommandFlags() {
return array_merge(
$this->getMandatoryFlags(),
nonempty($this->flags, $this->getDefaultFlags()));
}
public function getCacheVersion() {
try {
$this->checkBinaryConfiguration();
} catch (ArcanistMissingLinterException $e) {
return null;
}
$version = $this->getVersion();
if ($version) {
$this->checkBinaryVersion($version);
return $version.'-'.json_encode($this->getCommandFlags());
} else {
// Either we failed to parse the version number or the `getVersion`
// function hasn't been implemented.
return json_encode($this->getCommandFlags());
}
}
/**
* Prepare the path to be added to the command string.
*
* This method is expected to return an already escaped string.
*
* @param string Path to the file being linted
* @return string The command-ready file argument
*/
protected function getPathArgumentForLinterFuture($path) {
return csprintf('%s', $path);
}
final protected function buildFutures(array $paths) {
$executable = $this->getExecutableCommand();
$bin = csprintf('%C %Ls', $executable, $this->getCommandFlags());
$futures = array();
foreach ($paths as $path) {
$disk_path = $this->getEngine()->getFilePathOnDisk($path);
$path_argument = $this->getPathArgumentForLinterFuture($disk_path);
$future = new ExecFuture('%C %C', $bin, $path_argument);
$future->setCWD($this->getProjectRoot());
$futures[$path] = $future;
}
return $futures;
}
final protected function resolveFuture($path, Future $future) {
list($err, $stdout, $stderr) = $future->resolve();
if ($err && !$this->shouldExpectCommandErrors()) {
$future->resolvex();
}
$messages = $this->parseLinterOutput($path, $err, $stdout, $stderr);
if ($err && $this->shouldExpectCommandErrors() && !$messages) {
// We assume that if the future exits with a non-zero status and we
// failed to parse any linter messages, then something must've gone wrong
// during parsing.
$messages = false;
}
if ($messages === false) {
if ($err) {
$future->resolvex();
} else {
throw new Exception(
sprintf(
"%s\n\nSTDOUT\n%s\n\nSTDERR\n%s",
pht('Linter failed to parse output!'),
$stdout,
$stderr));
}
}
foreach ($messages as $message) {
$this->addLintMessage($message);
}
}
public function getLinterConfigurationOptions() {
$options = array(
'bin' => array(
'type' => 'optional string | list<string>',
'help' => pht(
'Specify a string (or list of strings) identifying the binary '.
'which should be invoked to execute this linter. This overrides '.
'the default binary. If you provide a list of possible binaries, '.
'the first one which exists will be used.'),
),
'flags' => array(
'type' => 'optional list<string>',
'help' => pht(
'Provide a list of additional flags to pass to the linter on the '.
'command line.'),
),
'version' => array(
'type' => 'optional string',
'help' => pht(
'Specify a version requirement for the binary. The version number '.
'may be prefixed with <, <=, >, >=, or = to specify the version '.
'comparison operator (default: =).'),
),
);
if ($this->shouldUseInterpreter()) {
$options['interpreter'] = array(
'type' => 'optional string | list<string>',
'help' => pht(
'Specify a string (or list of strings) identifying the interpreter '.
'which should be used to invoke the linter binary. If you provide '.
'a list of possible interpreters, the first one that exists '.
'will be used.'),
);
}
return $options + parent::getLinterConfigurationOptions();
}
public function setLinterConfigurationValue($key, $value) {
switch ($key) {
case 'interpreter':
$root = $this->getProjectRoot();
foreach ((array)$value as $path) {
if (Filesystem::binaryExists($path)) {
$this->setInterpreter($path);
return;
}
$path = Filesystem::resolvePath($path, $root);
if (Filesystem::binaryExists($path)) {
$this->setInterpreter($path);
return;
}
}
throw new Exception(
pht('None of the configured interpreters can be located.'));
case 'bin':
$is_script = $this->shouldUseInterpreter();
$root = $this->getProjectRoot();
foreach ((array)$value as $path) {
if (!$is_script && Filesystem::binaryExists($path)) {
$this->setBinary($path);
return;
}
$path = Filesystem::resolvePath($path, $root);
if ((!$is_script && Filesystem::binaryExists($path)) ||
($is_script && Filesystem::pathExists($path))) {
$this->setBinary($path);
return;
}
}
throw new Exception(
pht('None of the configured binaries can be located.'));
case 'flags':
$this->setFlags($value);
return;
case 'version':
$this->setVersionRequirement($value);
return;
}
return parent::setLinterConfigurationValue($key, $value);
}
/**
* Map a configuration lint code to an `arc` lint code. Primarily, this is
* intended for validation, but can also be used to normalize case or
* otherwise be more permissive in accepted inputs.
*
* If the code is not recognized, you should throw an exception.
*
* @param string Code specified in configuration.
* @return string Normalized code to use in severity map.
*/
protected function getLintCodeFromLinterConfigurationKey($code) {
return $code;
}
}

View file

@ -1,117 +0,0 @@
<?php
/**
* Uses "flake8" to detect various errors in Python code.
* Requires version 1.7.0 or newer of flake8.
*/
final class ArcanistFlake8Linter extends ArcanistExternalLinter {
public function getInfoName() {
return 'Python Flake8 multi-linter';
}
public function getInfoURI() {
return 'https://pypi.python.org/pypi/flake8';
}
public function getInfoDescription() {
return pht(
'Uses `%s` to run several linters (PyFlakes, pep8, and a McCabe '.
'complexity checker) on Python source files.',
'flake8');
}
public function getLinterName() {
return 'flake8';
}
public function getLinterConfigurationName() {
return 'flake8';
}
public function getDefaultBinary() {
return 'flake8';
}
public function getVersion() {
list($stdout) = execx('%C --version', $this->getExecutableCommand());
$matches = array();
if (preg_match('/^(?P<version>\d+\.\d+(?:\.\d+)?)\b/', $stdout, $matches)) {
return $matches['version'];
} else {
return false;
}
}
public function getInstallInstructions() {
return pht('Install flake8 using `%s`.', 'pip install flake8');
}
protected function parseLinterOutput($path, $err, $stdout, $stderr) {
$lines = phutil_split_lines($stdout, false);
// stdin:2: W802 undefined name 'foo' # pyflakes
// stdin:3:1: E302 expected 2 blank lines, found 1 # pep8
$regexp =
'/^(?:.*?):(?P<line>\d+):(?:(?P<char>\d+):)? (?P<code>\S+) (?P<msg>.*)$/';
$messages = array();
foreach ($lines as $line) {
$matches = null;
if (!preg_match($regexp, $line, $matches)) {
continue;
}
foreach ($matches as $key => $match) {
$matches[$key] = trim($match);
}
$message = new ArcanistLintMessage();
$message->setPath($path);
$message->setLine($matches['line']);
if (!empty($matches['char'])) {
$message->setChar($matches['char']);
}
$message->setCode($matches['code']);
$message->setName($this->getLinterName().' '.$matches['code']);
$message->setDescription($matches['msg']);
$message->setSeverity($this->getLintMessageSeverity($matches['code']));
$messages[] = $message;
}
return $messages;
}
protected function getDefaultMessageSeverity($code) {
if (preg_match('/^C/', $code)) {
// "C": Cyclomatic complexity
return ArcanistLintSeverity::SEVERITY_ADVICE;
} else if (preg_match('/^W/', $code)) {
// "W": PEP8 Warning
return ArcanistLintSeverity::SEVERITY_WARNING;
} else {
// "E": PEP8 Error
// "F": PyFlakes Error
// or: Flake8 Extension Message
return ArcanistLintSeverity::SEVERITY_ERROR;
}
}
protected function getLintCodeFromLinterConfigurationKey($code) {
if (!preg_match('/^[A-Z]\d+$/', $code)) {
throw new Exception(
pht(
'Unrecognized lint message code "%s". Expected a valid flake8 '.
'lint code like "%s", or "%s", or "%s", or "%s".',
$code,
'E225',
'W291',
'F811',
'C901'));
}
return $code;
}
}

View file

@ -1,56 +0,0 @@
<?php
abstract class ArcanistFutureLinter extends ArcanistLinter {
private $futures;
abstract protected function buildFutures(array $paths);
abstract protected function resolveFuture($path, Future $future);
final protected function getFuturesLimit() {
return 8;
}
final public function willLintPaths(array $paths) {
$limit = $this->getFuturesLimit();
$this->futures = id(new FutureIterator(array()))->limit($limit);
foreach ($this->buildFutures($paths) as $path => $future) {
$this->futures->addFuture($future, $path);
}
}
final public function lintPath($path) {
return;
}
final public function didLintPaths(array $paths) {
if (!$this->futures) {
return;
}
$map = array();
foreach ($this->futures as $path => $future) {
$this->setActivePath($path);
$this->resolveFuture($path, $future);
$map[$path] = $future;
}
$this->futures = array();
$this->didResolveLinterFutures($map);
}
/**
* Hook for cleaning up resources.
*
* This is invoked after a block of futures resolve, and allows linters to
* discard or clean up any shared resources they no longer need.
*
* @param map<string, Future> Map of paths to resolved futures.
* @return void
*/
protected function didResolveLinterFutures(array $futures) {
return;
}
}

View file

@ -1,67 +0,0 @@
<?php
final class ArcanistGoLintLinter extends ArcanistExternalLinter {
public function getInfoName() {
return 'Golint';
}
public function getInfoURI() {
return 'https://github.com/golang/lint';
}
public function getInfoDescription() {
return pht('Golint is a linter for Go source code.');
}
public function getLinterName() {
return 'GOLINT';
}
public function getLinterConfigurationName() {
return 'golint';
}
public function getDefaultBinary() {
return 'golint';
}
public function getInstallInstructions() {
return pht(
'Install Golint using `%s`.',
'go get github.com/golang/lint/golint');
}
public function shouldExpectCommandErrors() {
return false;
}
protected function canCustomizeLintSeverities() {
return true;
}
protected function parseLinterOutput($path, $err, $stdout, $stderr) {
$lines = phutil_split_lines($stdout, false);
$messages = array();
foreach ($lines as $line) {
$matches = explode(':', $line, 4);
if (count($matches) === 4) {
$message = new ArcanistLintMessage();
$message->setPath($path);
$message->setLine($matches[1]);
$message->setChar($matches[2]);
$message->setCode($this->getLinterName());
$message->setName($this->getLinterName());
$message->setDescription(ucfirst(trim($matches[3])));
$message->setSeverity(ArcanistLintSeverity::SEVERITY_ADVICE);
$messages[] = $message;
}
}
return $messages;
}
}

View file

@ -1,102 +0,0 @@
<?php
/**
* Calls `hlint` and parses its results.
*/
final class ArcanistHLintLinter extends ArcanistExternalLinter {
public function getInfoName() {
return 'Haskell Linter';
}
public function getInfoURI() {
return 'https://github.com/ndmitchell/hlint';
}
public function getInfoDescription() {
return pht('HLint is a linter for Haskell code.');
}
public function getLinterName() {
return 'HLINT';
}
public function getLinterConfigurationName() {
return 'hlint';
}
public function getDefaultBinary() {
return 'hlint';
}
public function getInstallInstructions() {
return pht('Install hlint with `%s`.', 'cabal install hlint');
}
protected function getMandatoryFlags() {
return array('--json');
}
public function getVersion() {
list($stdout, $stderr) = execx(
'%C --version', $this->getExecutableCommand());
$matches = null;
if (preg_match('@HLint v(.*),@', $stdout, $matches)) {
return $matches[1];
}
return null;
}
protected function parseLinterOutput($path, $err, $stdout, $stderr) {
$json = phutil_json_decode($stdout);
$messages = array();
foreach ($json as $fix) {
if ($fix === null) {
return;
}
$message = new ArcanistLintMessage();
$message->setCode($this->getLinterName());
$message->setPath($path);
$message->setLine($fix['startLine']);
$message->setChar($fix['startColumn']);
$message->setName($fix['hint']);
$message->setOriginalText($fix['from']);
$message->setReplacementText($fix['to']);
/* Some improvements may slightly change semantics, so attach
all necessary notes too. */
$notes = '';
foreach ($fix['note'] as $note) {
$notes .= phutil_console_format(
' **%s**: %s.',
pht('NOTE'),
trim($note, '"'));
}
$message->setDescription(
pht(
'In module `%s`, declaration `%s`.',
$fix['module'],
$fix['decl']).$notes);
switch ($fix['severity']) {
case 'Error':
$message->setSeverity(ArcanistLintSeverity::SEVERITY_ERROR);
break;
case 'Warning':
$message->setSeverity(ArcanistLintSeverity::SEVERITY_WARNING);
break;
default:
$message->setSeverity(ArcanistLintSeverity::SEVERITY_ADVICE);
break;
}
$messages[] = $message;
}
return $messages;
}
}

View file

@ -1,158 +0,0 @@
<?php
/**
* Uses JSHint to detect errors and potential problems in JavaScript code.
*/
final class ArcanistJSHintLinter extends ArcanistExternalLinter {
private $jshintignore;
private $jshintrc;
public function getInfoName() {
return 'JavaScript error checking';
}
public function getInfoURI() {
return 'http://www.jshint.com';
}
public function getInfoDescription() {
return pht(
'Use `%s` to detect issues with JavaScript source files.',
'jshint');
}
public function getLinterName() {
return 'JSHint';
}
public function getLinterConfigurationName() {
return 'jshint';
}
protected function getDefaultMessageSeverity($code) {
if (preg_match('/^W/', $code)) {
return ArcanistLintSeverity::SEVERITY_WARNING;
} else if (preg_match('/^E043$/', $code)) {
// TODO: If JSHint encounters a large number of errors, it will quit
// prematurely and add an additional "Too Many Errors" error. Ideally, we
// should be able to pass some sort of `--force` option to `jshint`.
//
// See https://github.com/jshint/jshint/issues/180
return ArcanistLintSeverity::SEVERITY_DISABLED;
} else {
return ArcanistLintSeverity::SEVERITY_ERROR;
}
}
public function getDefaultBinary() {
return 'jshint';
}
public function getVersion() {
// NOTE: `jshint --version` emits version information on stderr, not stdout.
list($stdout, $stderr) = execx(
'%C --version',
$this->getExecutableCommand());
$matches = array();
$regex = '/^jshint v(?P<version>\d+\.\d+\.\d+)$/';
if (preg_match($regex, $stderr, $matches)) {
return $matches['version'];
} else {
return false;
}
}
public function getInstallInstructions() {
return pht('Install JSHint using `%s`.', 'npm install -g jshint');
}
protected function getMandatoryFlags() {
$options = array();
$options[] = '--reporter='.dirname(realpath(__FILE__)).'/reporter.js';
if ($this->jshintrc) {
$options[] = '--config='.$this->jshintrc;
}
if ($this->jshintignore) {
$options[] = '--exclude-path='.$this->jshintignore;
}
return $options;
}
public function getLinterConfigurationOptions() {
$options = array(
'jshint.jshintignore' => array(
'type' => 'optional string',
'help' => pht('Pass in a custom jshintignore file path.'),
),
'jshint.jshintrc' => array(
'type' => 'optional string',
'help' => pht('Custom configuration file.'),
),
);
return $options + parent::getLinterConfigurationOptions();
}
public function setLinterConfigurationValue($key, $value) {
switch ($key) {
case 'jshint.jshintignore':
$this->jshintignore = $value;
return;
case 'jshint.jshintrc':
$this->jshintrc = $value;
return;
}
return parent::setLinterConfigurationValue($key, $value);
}
protected function parseLinterOutput($path, $err, $stdout, $stderr) {
$errors = null;
try {
$errors = phutil_json_decode($stdout);
} catch (PhutilJSONParserException $ex) {
// Something went wrong and we can't decode the output. Exit abnormally.
throw new PhutilProxyException(
pht('JSHint returned unparseable output.'),
$ex);
}
$messages = array();
foreach ($errors as $err) {
$message = new ArcanistLintMessage();
$message->setPath($path);
$message->setLine(idx($err, 'line'));
$message->setChar(idx($err, 'col'));
$message->setCode(idx($err, 'code'));
$message->setName('JSHint'.idx($err, 'code'));
$message->setDescription(idx($err, 'reason'));
$message->setSeverity($this->getLintMessageSeverity(idx($err, 'code')));
$messages[] = $message;
}
return $messages;
}
protected function getLintCodeFromLinterConfigurationKey($code) {
if (!preg_match('/^(E|W)\d+$/', $code)) {
throw new Exception(
pht(
'Unrecognized lint message code "%s". Expected a valid JSHint '.
'lint code like "%s" or "%s".',
$code,
'E033',
'W093'));
}
return $code;
}
}

View file

@ -1,86 +0,0 @@
<?php
/**
* A linter for JSON files.
*/
final class ArcanistJSONLintLinter extends ArcanistExternalLinter {
public function getInfoName() {
return pht('JSON Lint');
}
public function getInfoURI() {
return 'https://github.com/zaach/jsonlint';
}
public function getInfoDescription() {
return pht('Use `%s` to detect syntax errors in JSON files.', 'jsonlint');
}
public function getLinterName() {
return 'JSON';
}
public function getLinterConfigurationName() {
return 'jsonlint';
}
public function getDefaultBinary() {
return 'jsonlint';
}
public function getVersion() {
// NOTE: `jsonlint --version` returns a non-zero exit status.
list($err, $stdout) = exec_manual(
'%C --version',
$this->getExecutableCommand());
$matches = array();
if (preg_match('/^(?P<version>\d+\.\d+\.\d+)$/', $stdout, $matches)) {
return $matches['version'];
} else {
return false;
}
}
public function getInstallInstructions() {
return pht('Install jsonlint using `%s`.', 'npm install -g jsonlint');
}
protected function getMandatoryFlags() {
return array(
'--compact',
);
}
protected function parseLinterOutput($path, $err, $stdout, $stderr) {
$lines = phutil_split_lines($stderr, false);
$messages = array();
foreach ($lines as $line) {
$matches = null;
$match = preg_match(
'/^(?:(?<path>.+): )?'.
'line (?<line>\d+), col (?<column>\d+), '.
'(?<description>.*)$/',
$line,
$matches);
if ($match) {
$message = new ArcanistLintMessage();
$message->setPath($path);
$message->setLine($matches['line']);
$message->setChar($matches['column']);
$message->setCode($this->getLinterName());
$message->setName($this->getLinterName());
$message->setDescription(ucfirst($matches['description']));
$message->setSeverity(ArcanistLintSeverity::SEVERITY_ERROR);
$messages[] = $message;
}
}
return $messages;
}
}

View file

@ -1,149 +0,0 @@
<?php
final class ArcanistJscsLinter extends ArcanistExternalLinter {
private $config;
private $preset;
public function getInfoName() {
return 'JavaScript Code Style';
}
public function getInfoURI() {
return 'https://github.com/mdevils/node-jscs';
}
public function getInfoDescription() {
return pht(
'Use `%s` to detect issues with Javascript source files.',
'jscs');
}
public function getLinterName() {
return 'JSCS';
}
public function getLinterConfigurationName() {
return 'jscs';
}
public function getDefaultBinary() {
return 'jscs';
}
public function getVersion() {
list($stdout) = execx('%C --version', $this->getExecutableCommand());
$matches = array();
$regex = '/^(?P<version>\d+\.\d+\.\d+)$/';
if (preg_match($regex, $stdout, $matches)) {
return $matches['version'];
} else {
return false;
}
}
public function getInstallInstructions() {
return pht('Install JSCS using `%s`.', 'npm install -g jscs');
}
protected function getMandatoryFlags() {
$options = array();
$options[] = '--reporter=checkstyle';
$options[] = '--no-colors';
if ($this->config) {
$options[] = '--config='.$this->config;
}
if ($this->preset) {
$options[] = '--preset='.$this->preset;
}
return $options;
}
public function getLinterConfigurationOptions() {
$options = array(
'jscs.config' => array(
'type' => 'optional string',
'help' => pht('Pass in a custom %s file path.', 'jscsrc'),
),
'jscs.preset' => array(
'type' => 'optional string',
'help' => pht('Custom preset.'),
),
);
return $options + parent::getLinterConfigurationOptions();
}
public function setLinterConfigurationValue($key, $value) {
switch ($key) {
case 'jscs.config':
$this->config = $value;
return;
case 'jscs.preset':
$this->preset = $value;
return;
}
return parent::setLinterConfigurationValue($key, $value);
}
protected function parseLinterOutput($path, $err, $stdout, $stderr) {
$report_dom = new DOMDocument();
$ok = @$report_dom->loadXML($stdout);
if (!$ok) {
return false;
}
$messages = array();
foreach ($report_dom->getElementsByTagName('file') as $file) {
foreach ($file->getElementsByTagName('error') as $error) {
$message = new ArcanistLintMessage();
$message->setPath($path);
$message->setLine($error->getAttribute('line'));
$message->setChar($error->getAttribute('column'));
$message->setCode('JSCS');
$message->setName('JSCS');
$message->setDescription($error->getAttribute('message'));
switch ($error->getAttribute('severity')) {
case 'error':
$message->setSeverity(ArcanistLintSeverity::SEVERITY_ERROR);
break;
case 'warning':
$message->setSeverity(ArcanistLintSeverity::SEVERITY_WARNING);
break;
default:
$message->setSeverity(ArcanistLintSeverity::SEVERITY_ADVICE);
break;
}
$messages[] = $message;
}
}
return $messages;
}
protected function getLintCodeFromLinterConfigurationKey($code) {
// NOTE: We can't figure out which rule generated each message, so we
// can not customize severities.
//
// See https://github.com/mdevils/node-jscs/issues/224
throw new Exception(
pht(
"JSCS does not currently support custom severity levels, because ".
"rules can't be identified from messages in output."));
}
}

View file

@ -1,183 +0,0 @@
<?php
/**
* A linter for LESSCSS files.
*
* This linter uses [[https://github.com/less/less.js | lessc]] to detect
* errors and potential problems in [[http://lesscss.org/ | LESS]] code.
*/
final class ArcanistLesscLinter extends ArcanistExternalLinter {
const LINT_RUNTIME_ERROR = 1;
const LINT_ARGUMENT_ERROR = 2;
const LINT_FILE_ERROR = 3;
const LINT_NAME_ERROR = 4;
const LINT_OPERATION_ERROR = 5;
const LINT_PARSE_ERROR = 6;
const LINT_SYNTAX_ERROR = 7;
private $strictMath = false;
private $strictUnits = false;
public function getInfoName() {
return 'CSS pre-processor';
}
public function getInfoURI() {
return 'http://lesscss.org/';
}
public function getInfoDescription() {
return pht(
'Use the `%s` mode provided by `%s` to detect errors in '.
'Less source files.',
'--lint',
'lessc');
}
public function getLinterName() {
return 'LESSC';
}
public function getLinterConfigurationName() {
return 'lessc';
}
public function getLinterConfigurationOptions() {
return parent::getLinterConfigurationOptions() + array(
'lessc.strict-math' => array(
'type' => 'optional bool',
'help' => pht(
'Enable strict math, which only processes mathematical expressions '.
'inside extraneous parentheses.'),
),
'lessc.strict-units' => array(
'type' => 'optional bool',
'help' => pht('Enable strict handling of units in expressions.'),
),
);
}
public function setLinterConfigurationValue($key, $value) {
switch ($key) {
case 'lessc.strict-math':
$this->strictMath = $value;
return;
case 'lessc.strict-units':
$this->strictUnits = $value;
return;
}
return parent::setLinterConfigurationValue($key, $value);
}
public function getLintNameMap() {
return array(
self::LINT_RUNTIME_ERROR => pht('Runtime Error'),
self::LINT_ARGUMENT_ERROR => pht('Argument Error'),
self::LINT_FILE_ERROR => pht('File Error'),
self::LINT_NAME_ERROR => pht('Name Error'),
self::LINT_OPERATION_ERROR => pht('Operation Error'),
self::LINT_PARSE_ERROR => pht('Parse Error'),
self::LINT_SYNTAX_ERROR => pht('Syntax Error'),
);
}
public function getDefaultBinary() {
return 'lessc';
}
public function getVersion() {
list($stdout) = execx('%C --version', $this->getExecutableCommand());
$matches = array();
$regex = '/^lessc (?P<version>\d+\.\d+\.\d+)\b/';
if (preg_match($regex, $stdout, $matches)) {
$version = $matches['version'];
} else {
return false;
}
}
public function getInstallInstructions() {
return pht('Install lessc using `%s`.', 'npm install -g less');
}
protected function getMandatoryFlags() {
return array(
'--lint',
'--no-color',
'--strict-math='.($this->strictMath ? 'on' : 'off'),
'--strict-units='.($this->strictUnits ? 'on' : 'off'),
);
}
protected function parseLinterOutput($path, $err, $stdout, $stderr) {
$lines = phutil_split_lines($stderr, false);
$messages = array();
foreach ($lines as $line) {
$matches = null;
$match = preg_match(
'/^(?P<name>\w+): (?P<description>.+) '.
'in (?P<path>.+|-) '.
'on line (?P<line>\d+), column (?P<column>\d+):$/',
$line,
$matches);
if ($match) {
switch ($matches['name']) {
case 'RuntimeError':
$code = self::LINT_RUNTIME_ERROR;
break;
case 'ArgumentError':
$code = self::LINT_ARGUMENT_ERROR;
break;
case 'FileError':
$code = self::LINT_FILE_ERROR;
break;
case 'NameError':
$code = self::LINT_NAME_ERROR;
break;
case 'OperationError':
$code = self::LINT_OPERATION_ERROR;
break;
case 'ParseError':
$code = self::LINT_PARSE_ERROR;
break;
case 'SyntaxError':
$code = self::LINT_SYNTAX_ERROR;
break;
default:
throw new RuntimeException(
pht(
'Unrecognized lint message code "%s".',
$code));
}
$code = $this->getLintCodeFromLinterConfigurationKey($matches['name']);
$message = new ArcanistLintMessage();
$message->setPath($path);
$message->setLine($matches['line']);
$message->setChar($matches['column']);
$message->setCode($this->getLintMessageFullCode($code));
$message->setSeverity($this->getLintMessageSeverity($code));
$message->setName($this->getLintMessageName($code));
$message->setDescription(ucfirst($matches['description']));
$messages[] = $message;
}
}
return $messages;
}
}

View file

@ -1,98 +0,0 @@
<?php
/**
* Uses "pep8.py" to enforce PEP8 rules for Python.
*/
final class ArcanistPEP8Linter extends ArcanistExternalLinter {
public function getInfoName() {
return 'Python PEP 8';
}
public function getInfoURI() {
return 'https://pypi.python.org/pypi/pep8';
}
public function getInfoDescription() {
return pht(
'pep8 is a tool to check your Python code against some of the '.
'style conventions in PEP 8.');
}
public function getLinterName() {
return 'PEP8';
}
public function getLinterConfigurationName() {
return 'pep8';
}
public function getDefaultBinary() {
return 'pep8';
}
public function getVersion() {
list($stdout) = execx('%C --version', $this->getExecutableCommand());
$matches = array();
if (preg_match('/^(?P<version>\d+\.\d+(?:\.\d+)?)\b/', $stdout, $matches)) {
return $matches['version'];
} else {
return false;
}
}
public function getInstallInstructions() {
return pht('Install PEP8 using `%s`.', 'pip install pep8');
}
protected function parseLinterOutput($path, $err, $stdout, $stderr) {
$lines = phutil_split_lines($stdout, false);
$messages = array();
foreach ($lines as $line) {
$matches = null;
if (!preg_match('/^(.*?):(\d+):(\d+): (\S+) (.*)$/', $line, $matches)) {
continue;
}
foreach ($matches as $key => $match) {
$matches[$key] = trim($match);
}
$message = new ArcanistLintMessage();
$message->setPath($path);
$message->setLine($matches[2]);
$message->setChar($matches[3]);
$message->setCode($matches[4]);
$message->setName('PEP8 '.$matches[4]);
$message->setDescription($matches[5]);
$message->setSeverity($this->getLintMessageSeverity($matches[4]));
$messages[] = $message;
}
return $messages;
}
protected function getDefaultMessageSeverity($code) {
if (preg_match('/^W/', $code)) {
return ArcanistLintSeverity::SEVERITY_WARNING;
} else {
return ArcanistLintSeverity::SEVERITY_ERROR;
}
}
protected function getLintCodeFromLinterConfigurationKey($code) {
if (!preg_match('/^(E|W)\d+$/', $code)) {
throw new Exception(
pht(
'Unrecognized lint message code "%s". Expected a valid PEP8 '.
'lint code like "%s" or "%s".',
$code,
'E101',
'W291'));
}
return $code;
}
}

View file

@ -1,101 +0,0 @@
<?php
/**
* Uses "php -l" to detect syntax errors in PHP code.
*/
final class ArcanistPhpLinter extends ArcanistExternalLinter {
const LINT_PARSE_ERROR = 1;
const LINT_FATAL_ERROR = 2;
public function getInfoName() {
return 'php -l';
}
public function getInfoURI() {
return 'http://php.net/';
}
public function getInfoDescription() {
return pht('Checks for syntax errors in PHP files.');
}
public function getLinterName() {
return 'PHP';
}
public function getLinterConfigurationName() {
return 'php';
}
public function getLintNameMap() {
return array(
self::LINT_PARSE_ERROR => pht('Parse Error'),
self::LINT_FATAL_ERROR => pht('Fatal Error'),
);
}
protected function getMandatoryFlags() {
return array('-l');
}
public function getInstallInstructions() {
return pht('Install PHP.');
}
public function getDefaultBinary() {
return 'php';
}
public function getVersion() {
list($stdout) = execx(
'%C --run %s',
$this->getExecutableCommand(),
'echo phpversion();');
return $stdout;
}
protected function canCustomizeLintSeverities() {
return false;
}
protected function parseLinterOutput($path, $err, $stdout, $stderr) {
// Older versions of PHP had both on stdout, newer ones split it.
// Combine stdout and stderr for consistency.
$stdout = $stderr."\n".$stdout;
$matches = array();
$regex = '/^(PHP )?(?<type>.+) error: +(?<error>.+) in (?<file>.+) '.
'on line (?<line>\d+)$/m';
if (preg_match($regex, $stdout, $matches)) {
$code = $this->getLintCodeFromLinterConfigurationKey($matches['type']);
$message = id(new ArcanistLintMessage())
->setPath($path)
->setLine($matches['line'])
->setCode($this->getLinterName().$code)
->setName($this->getLintMessageName($code))
->setSeverity(ArcanistLintSeverity::SEVERITY_ERROR)
->setDescription($matches['error']);
// `php -l` only returns the first error.
return array($message);
}
return array();
}
protected function getLintCodeFromLinterConfigurationKey($code) {
switch (phutil_utf8_strtolower($code)) {
case 'parse':
return self::LINT_PARSE_ERROR;
case 'fatal':
return self::LINT_FATAL_ERROR;
default:
throw new Exception(pht('Unrecognized lint message code: "%s"', $code));
}
}
}

View file

@ -1,150 +0,0 @@
<?php
/**
* Uses "PHP_CodeSniffer" to detect checkstyle errors in PHP code.
*/
final class ArcanistPhpcsLinter extends ArcanistExternalLinter {
private $standard;
public function getInfoName() {
return 'PHP_CodeSniffer';
}
public function getInfoURI() {
return 'http://pear.php.net/package/PHP_CodeSniffer/';
}
public function getInfoDescription() {
return pht(
'PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and '.
'detects violations of a defined set of coding standards.');
}
public function getLinterName() {
return 'PHPCS';
}
public function getLinterConfigurationName() {
return 'phpcs';
}
public function getInstallInstructions() {
return pht('Install PHPCS with `%s`.', 'pear install PHP_CodeSniffer');
}
public function getLinterConfigurationOptions() {
$options = array(
'phpcs.standard' => array(
'type' => 'optional string',
'help' => pht('The name or path of the coding standard to use.'),
),
);
return $options + parent::getLinterConfigurationOptions();
}
public function setLinterConfigurationValue($key, $value) {
switch ($key) {
case 'phpcs.standard':
$this->standard = $value;
return;
default:
return parent::setLinterConfigurationValue($key, $value);
}
}
protected function getMandatoryFlags() {
$options = array('--report=xml');
if ($this->standard) {
$options[] = '--standard='.$this->standard;
}
return $options;
}
public function getDefaultBinary() {
return 'phpcs';
}
public function getVersion() {
list($stdout) = execx('%C --version', $this->getExecutableCommand());
$matches = array();
$regex = '/^PHP_CodeSniffer version (?P<version>\d+\.\d+\.\d+)\b/';
if (preg_match($regex, $stdout, $matches)) {
return $matches['version'];
} else {
return false;
}
}
protected function parseLinterOutput($path, $err, $stdout, $stderr) {
// NOTE: Some version of PHPCS after 1.4.6 stopped printing a valid, empty
// XML document to stdout in the case of no errors. If PHPCS exits with
// error 0, just ignore output.
if (!$err) {
return array();
}
$report_dom = new DOMDocument();
$ok = @$report_dom->loadXML($stdout);
if (!$ok) {
return false;
}
$files = $report_dom->getElementsByTagName('file');
$messages = array();
foreach ($files as $file) {
foreach ($file->childNodes as $child) {
if (!($child instanceof DOMElement)) {
continue;
}
if ($child->tagName == 'error') {
$prefix = 'E';
} else {
$prefix = 'W';
}
$source = $child->getAttribute('source');
$code = 'PHPCS.'.$prefix.'.'.$source;
$message = id(new ArcanistLintMessage())
->setPath($path)
->setName($source)
->setLine($child->getAttribute('line'))
->setChar($child->getAttribute('column'))
->setCode($code)
->setDescription($child->nodeValue)
->setSeverity($this->getLintMessageSeverity($code));
$messages[] = $message;
}
}
return $messages;
}
protected function getDefaultMessageSeverity($code) {
if (preg_match('/^PHPCS\\.W\\./', $code)) {
return ArcanistLintSeverity::SEVERITY_WARNING;
} else {
return ArcanistLintSeverity::SEVERITY_ERROR;
}
}
protected function getLintCodeFromLinterConfigurationKey($code) {
if (!preg_match('/^PHPCS\\.(E|W)\\./', $code)) {
throw new Exception(
pht(
"Invalid severity code '%s', should begin with '%s.'.",
$code,
'PHPCS'));
}
return $code;
}
}

View file

@ -1,139 +0,0 @@
<?php
/**
* A linter for Puppet files.
*/
final class ArcanistPuppetLintLinter extends ArcanistExternalLinter {
private $config;
public function getInfoName() {
return 'puppet-lint';
}
public function getInfoURI() {
return 'http://puppet-lint.com/';
}
public function getInfoDescription() {
return pht(
'Use `%s` to check that your Puppet manifests '.
'conform to the style guide.',
'puppet-lint');
}
public function getLinterName() {
return 'PUPPETLINT';
}
public function getLinterConfigurationName() {
return 'puppet-lint';
}
public function getDefaultBinary() {
return 'puppet-lint';
}
public function getVersion() {
list($stdout) = execx('%C --version', $this->getExecutableCommand());
$matches = array();
$regex = '/^puppet-lint (?P<version>\d+\.\d+\.\d+)$/';
if (preg_match($regex, $stdout, $matches)) {
return $matches['version'];
} else {
return false;
}
}
public function getInstallInstructions() {
return pht(
'Install puppet-lint using `%s`.',
'gem install puppet-lint');
}
protected function getMandatoryFlags() {
return array(
'--error-level=all',
sprintf('--log-format=%s', implode('|', array(
'%{linenumber}',
'%{column}',
'%{kind}',
'%{check}',
'%{message}',
))),
);
}
public function getLinterConfigurationOptions() {
$options = array(
'puppet-lint.config' => array(
'type' => 'optional string',
'help' => pht('Pass in a custom configuration file path.'),
),
);
return $options + parent::getLinterConfigurationOptions();
}
public function setLinterConfigurationValue($key, $value) {
switch ($key) {
case 'puppet-lint.config':
$this->config = $value;
return;
default:
return parent::setLinterConfigurationValue($key, $value);
}
}
protected function getDefaultFlags() {
$options = array();
if ($this->config) {
$options[] = '--config='.$this->config;
}
return $options;
}
protected function parseLinterOutput($path, $err, $stdout, $stderr) {
$lines = phutil_split_lines($stdout, false);
$messages = array();
foreach ($lines as $line) {
$matches = explode('|', $line, 5);
if (count($matches) < 5) {
continue;
}
$message = id(new ArcanistLintMessage())
->setPath($path)
->setLine($matches[0])
->setChar($matches[1])
->setCode($this->getLinterName())
->setName(ucwords(str_replace('_', ' ', $matches[3])))
->setDescription(ucfirst($matches[4]));
switch ($matches[2]) {
case 'warning':
$message->setSeverity(ArcanistLintSeverity::SEVERITY_WARNING);
break;
case 'error':
$message->setSeverity(ArcanistLintSeverity::SEVERITY_ERROR);
break;
default:
$message->setSeverity(ArcanistLintSeverity::SEVERITY_ADVICE);
break;
}
$messages[] = $message;
}
return $messages;
}
}

View file

@ -1,88 +0,0 @@
<?php
/**
* Uses "PyFlakes" to detect various errors in Python code.
*/
final class ArcanistPyFlakesLinter extends ArcanistExternalLinter {
public function getInfoURI() {
return 'https://pypi.python.org/pypi/pyflakes';
}
public function getInfoName() {
return pht('Python PyFlakes');
}
public function getInfoDescription() {
return pht(
'PyFlakes is a simple program which checks Python source files for '.
'errors.');
}
public function getLinterName() {
return 'PYFLAKES';
}
public function getLinterConfigurationName() {
return 'pyflakes';
}
public function getDefaultBinary() {
return 'pyflakes';
}
public function getVersion() {
list($stdout) = execx('%C --version', $this->getExecutableCommand());
$matches = array();
if (preg_match('/^(?P<version>\d+\.\d+\.\d+)$/', $stdout, $matches)) {
return $matches['version'];
} else {
return false;
}
}
public function getInstallInstructions() {
return pht('Install pyflakes with `%s`.', 'pip install pyflakes');
}
protected function parseLinterOutput($path, $err, $stdout, $stderr) {
$lines = phutil_split_lines($stdout, false);
$messages = array();
foreach ($lines as $line) {
$matches = null;
if (!preg_match('/^(.*?):(\d+): (.*)$/', $line, $matches)) {
continue;
}
foreach ($matches as $key => $match) {
$matches[$key] = trim($match);
}
$severity = ArcanistLintSeverity::SEVERITY_WARNING;
$description = $matches[3];
$error_regexp = '/(^undefined|^duplicate|before assignment$)/';
if (preg_match($error_regexp, $description)) {
$severity = ArcanistLintSeverity::SEVERITY_ERROR;
}
$message = new ArcanistLintMessage();
$message->setPath($path);
$message->setLine($matches[2]);
$message->setCode($this->getLinterName());
$message->setName($this->getLinterName());
$message->setDescription($description);
$message->setSeverity($severity);
$messages[] = $message;
}
return $messages;
}
protected function canCustomizeLintSeverities() {
return false;
}
}

View file

@ -1,183 +0,0 @@
<?php
/**
* Uses "PyLint" to detect various errors in Python code.
*/
final class ArcanistPyLintLinter extends ArcanistExternalLinter {
private $config;
public function getInfoName() {
return 'PyLint';
}
public function getInfoURI() {
return 'http://www.pylint.org/';
}
public function getInfoDescription() {
return pht(
'PyLint is a Python source code analyzer which looks for '.
'programming errors, helps enforcing a coding standard and '.
'sniffs for some code smells.');
}
public function getLinterName() {
return 'PyLint';
}
public function getLinterConfigurationName() {
return 'pylint';
}
public function getDefaultBinary() {
return 'pylint';
}
public function getVersion() {
list($stdout) = execx('%C --version', $this->getExecutableCommand());
$matches = array();
$regex = '/^pylint (?P<version>\d+\.\d+\.\d+),/';
if (preg_match($regex, $stdout, $matches)) {
return $matches['version'];
} else {
return false;
}
}
public function getInstallInstructions() {
return pht(
'Install PyLint using `%s`.',
'pip install pylint');
}
public function shouldExpectCommandErrors() {
return true;
}
public function getLinterConfigurationOptions() {
$options = array(
'pylint.config' => array(
'type' => 'optional string',
'help' => pht('Pass in a custom configuration file path.'),
),
);
return $options + parent::getLinterConfigurationOptions();
}
public function setLinterConfigurationValue($key, $value) {
switch ($key) {
case 'pylint.config':
$this->config = $value;
return;
default:
return parent::setLinterConfigurationValue($key, $value);
}
}
protected function getMandatoryFlags() {
$options = array();
$options[] = '--reports=no';
$options[] = '--msg-template={line}|{column}|{msg_id}|{symbol}|{msg}';
// Specify an `--rcfile`, either absolute or relative to the project root.
// Stupidly, the command line args above are overridden by rcfile, so be
// careful.
$config = $this->config;
if ($config !== null) {
$options[] = '--rcfile='.$config;
}
return $options;
}
protected function getDefaultFlags() {
$options = array();
$installed_version = $this->getVersion();
$minimum_version = '1.0.0';
if (version_compare($installed_version, $minimum_version, '<')) {
throw new ArcanistMissingLinterException(
pht(
'%s is not compatible with the installed version of pylint. '.
'Minimum version: %s; installed version: %s.',
__CLASS__,
$minimum_version,
$installed_version));
}
return $options;
}
protected function parseLinterOutput($path, $err, $stdout, $stderr) {
if ($err === 32) {
// According to `man pylint` the exit status of 32 means there was a
// usage error. That's bad, so actually exit abnormally.
return false;
}
$lines = phutil_split_lines($stdout, false);
$messages = array();
foreach ($lines as $line) {
$matches = explode('|', $line, 5);
if (count($matches) < 5) {
continue;
}
// NOTE: PyLint sometimes returns -1 as the character offset for a
// message. If it does, treat it as 0. See T9257.
$char = (int)$matches[1];
$char = max(0, $char);
$message = id(new ArcanistLintMessage())
->setPath($path)
->setLine($matches[0])
->setChar($char)
->setCode($matches[2])
->setSeverity($this->getLintMessageSeverity($matches[2]))
->setName(ucwords(str_replace('-', ' ', $matches[3])))
->setDescription($matches[4]);
$messages[] = $message;
}
return $messages;
}
protected function getDefaultMessageSeverity($code) {
switch (substr($code, 0, 1)) {
case 'R':
case 'C':
return ArcanistLintSeverity::SEVERITY_ADVICE;
case 'W':
return ArcanistLintSeverity::SEVERITY_WARNING;
case 'E':
case 'F':
return ArcanistLintSeverity::SEVERITY_ERROR;
default:
return ArcanistLintSeverity::SEVERITY_DISABLED;
}
}
protected function getLintCodeFromLinterConfigurationKey($code) {
if (!preg_match('/^(R|C|W|E|F)\d{4}$/', $code)) {
throw new Exception(
pht(
'Unrecognized lint message code "%s". Expected a valid Pylint '.
'lint code like "%s", or "%s", or "%s".',
$code,
'C0111',
'E0602',
'W0611'));
}
return $code;
}
}

View file

@ -1,120 +0,0 @@
<?php
final class ArcanistRuboCopLinter extends ArcanistExternalLinter {
private $config;
public function getInfoName() {
return 'Ruby static code analyzer';
}
public function getInfoURI() {
return 'http://batsov.com/rubocop';
}
public function getInfoDescription() {
return pht(
'RuboCop is a Ruby static code analyzer, based on the community Ruby '.
'style guide.');
}
public function getLinterName() {
return 'RuboCop';
}
public function getLinterConfigurationName() {
return 'rubocop';
}
public function getDefaultBinary() {
return 'rubocop';
}
public function getVersion() {
list($stdout) = execx('%C --version', $this->getExecutableCommand());
$matches = array();
if (preg_match('/^(?P<version>\d+\.\d+\.\d+)$/', $stdout, $matches)) {
return $matches['version'];
} else {
return false;
}
}
public function getInstallInstructions() {
return pht('Install RuboCop using `%s`.', 'gem install rubocop');
}
protected function getMandatoryFlags() {
$options = array(
'--format=json',
);
if ($this->config) {
$options[] = '--config='.$this->config;
}
return $options;
}
public function getLinterConfigurationOptions() {
$options = array(
'rubocop.config' => array(
'type' => 'optional string',
'help' => pht('A custom configuration file.'),
),
);
return $options + parent::getLinterConfigurationOptions();
}
public function setLinterConfigurationValue($key, $value) {
switch ($key) {
case 'rubocop.config':
$this->config = $value;
return;
}
return parent::setLinterConfigurationValue($key, $value);
}
protected function parseLinterOutput($path, $err, $stdout, $stderr) {
$results = phutil_json_decode($stdout);
$messages = array();
foreach ($results['files'] as $file) {
foreach ($file['offenses'] as $offense) {
$message = id(new ArcanistLintMessage())
->setPath($file['path'])
->setDescription($offense['message'])
->setLine($offense['location']['line'])
->setChar($offense['location']['column'])
->setSeverity($this->getLintMessageSeverity($offense['severity']))
->setName($this->getLinterName())
->setCode($offense['cop_name']);
$messages[] = $message;
}
}
return $messages;
}
/**
* Take the string from RuboCop's severity terminology and return an
* @{class:ArcanistLintSeverity}.
*/
protected function getDefaultMessageSeverity($code) {
switch ($code) {
case 'convention':
case 'refactor':
case 'warning':
return ArcanistLintSeverity::SEVERITY_WARNING;
case 'error':
case 'fatal':
return ArcanistLintSeverity::SEVERITY_ERROR;
default:
return ArcanistLintSeverity::SEVERITY_ADVICE;
}
}
}

View file

@ -1,87 +0,0 @@
<?php
/**
* Uses `ruby` to detect various errors in Ruby code.
*/
final class ArcanistRubyLinter extends ArcanistExternalLinter {
public function getInfoURI() {
return 'https://www.ruby-lang.org/';
}
public function getInfoName() {
return pht('Ruby');
}
public function getInfoDescription() {
return pht(
'Use `%s` to check for syntax errors in Ruby source files.',
'ruby');
}
public function getLinterName() {
return 'RUBY';
}
public function getLinterConfigurationName() {
return 'ruby';
}
public function getDefaultBinary() {
return 'ruby';
}
public function getVersion() {
list($stdout) = execx('%C --version', $this->getExecutableCommand());
$matches = array();
$regex = '/^ruby (?P<version>\d+\.\d+\.\d+)+/';
if (preg_match($regex, $stdout, $matches)) {
return $matches['version'];
} else {
return false;
}
}
public function getInstallInstructions() {
return pht('Install `%s` from <%s>.', 'ruby', 'http://www.ruby-lang.org/');
}
protected function getMandatoryFlags() {
// -w: turn on warnings
// -c: check syntax
return array('-w', '-c');
}
protected function parseLinterOutput($path, $err, $stdout, $stderr) {
$lines = phutil_split_lines($stderr, false);
$messages = array();
foreach ($lines as $line) {
$matches = null;
if (!preg_match('/(.*?):(\d+): (.*?)$/', $line, $matches)) {
continue;
}
foreach ($matches as $key => $match) {
$matches[$key] = trim($match);
}
$code = head(explode(',', $matches[3]));
$message = new ArcanistLintMessage();
$message->setPath($path);
$message->setLine($matches[2]);
$message->setCode($this->getLinterName());
$message->setName(pht('Syntax Error'));
$message->setDescription($matches[3]);
$message->setSeverity($this->getLintMessageSeverity($code));
$messages[] = $message;
}
return $messages;
}
}

View file

@ -1,392 +0,0 @@
<?php
/**
* Simple glue linter which runs some script on each path, and then uses a
* regex to parse lint messages from the script's output. (This linter uses a
* script and a regex to interpret the results of some real linter, it does
* not itself lint both scripts and regexes).
*
* Configure this linter by setting these keys in your .arclint section:
*
* - `script-and-regex.script` Script command to run. This can be
* the path to a linter script, but may also include flags or use shell
* features (see below for examples).
* - `script-and-regex.regex` The regex to process output with. This
* regex uses named capturing groups (detailed below) to interpret output.
*
* The script will be invoked from the project root, so you can specify a
* relative path like `scripts/lint.sh` or an absolute path like
* `/opt/lint/lint.sh`.
*
* This linter is necessarily more limited in its capabilities than a normal
* linter which can perform custom processing, but may be somewhat simpler to
* configure.
*
* == Script... ==
*
* The script will be invoked once for each file that is to be linted, with
* the file passed as the first argument. The file may begin with a "-"; ensure
* your script will not interpret such files as flags (perhaps by ending your
* script configuration with "--", if its argument parser supports that).
*
* Note that when run via `arc diff`, the list of files to be linted includes
* deleted files and files that were moved away by the change. The linter should
* not assume the path it is given exists, and it is not an error for the
* linter to be invoked with paths which are no longer there. (Every affected
* path is subject to lint because some linters may raise errors in other files
* when a file is removed, or raise an error about its removal.)
*
* The script should emit lint messages to stdout, which will be parsed with
* the provided regex.
*
* For example, you might use a configuration like this:
*
* /opt/lint/lint.sh --flag value --other-flag --
*
* stderr is ignored. If you have a script which writes messages to stderr,
* you can redirect stderr to stdout by using a configuration like this:
*
* sh -c '/opt/lint/lint.sh "$0" 2>&1'
*
* The return code of the script must be 0, or an exception will be raised
* reporting that the linter failed. If you have a script which exits nonzero
* under normal circumstances, you can force it to always exit 0 by using a
* configuration like this:
*
* sh -c '/opt/lint/lint.sh "$0" || true'
*
* Multiple instances of the script will be run in parallel if there are
* multiple files to be linted, so they should not use any unique resources.
* For instance, this configuration would not work properly, because several
* processes may attempt to write to the file at the same time:
*
* COUNTEREXAMPLE
* sh -c '/opt/lint/lint.sh --output /tmp/lint.out "$0" && cat /tmp/lint.out'
*
* There are necessary limits to how gracefully this linter can deal with
* edge cases, because it is just a script and a regex. If you need to do
* things that this linter can't handle, you can write a phutil linter and move
* the logic to handle those cases into PHP. PHP is a better general-purpose
* programming language than regular expressions are, if only by a small margin.
*
* == ...and Regex ==
*
* The regex must be a valid PHP PCRE regex, including delimiters and flags.
*
* The regex will be matched against the entire output of the script, so it
* should generally be in this form if messages are one-per-line:
*
* /^...$/m
*
* The regex should capture these named patterns with `(?P<name>...)`:
*
* - `message` (required) Text describing the lint message. For example,
* "This is a syntax error.".
* - `name` (optional) Text summarizing the lint message. For example,
* "Syntax Error".
* - `severity` (optional) The word "error", "warning", "autofix", "advice",
* or "disabled", in any combination of upper and lower case. Instead, you
* may match groups called `error`, `warning`, `advice`, `autofix`, or
* `disabled`. These allow you to match output formats like "E123" and
* "W123" to indicate errors and warnings, even though the word "error" is
* not present in the output. If no severity capturing group is present,
* messages are raised with "error" severity. If multiple severity capturing
* groups are present, messages are raised with the highest captured
* severity. Capturing groups like `error` supersede the `severity`
* capturing group.
* - `error` (optional) Match some nonempty substring to indicate that this
* message has "error" severity.
* - `warning` (optional) Match some nonempty substring to indicate that this
* message has "warning" severity.
* - `advice` (optional) Match some nonempty substring to indicate that this
* message has "advice" severity.
* - `autofix` (optional) Match some nonempty substring to indicate that this
* message has "autofix" severity.
* - `disabled` (optional) Match some nonempty substring to indicate that this
* message has "disabled" severity.
* - `file` (optional) The name of the file to raise the lint message in. If
* not specified, defaults to the linted file. It is generally not necessary
* to capture this unless the linter can raise messages in files other than
* the one it is linting.
* - `line` (optional) The line number of the message. If no text is
* captured, the message is assumed to affect the entire file.
* - `char` (optional) The character offset of the message.
* - `offset` (optional) The byte offset of the message. If captured, this
* supersedes `line` and `char`.
* - `original` (optional) The text the message affects.
* - `replacement` (optional) The text that the range captured by `original`
* should be automatically replaced by to resolve the message.
* - `code` (optional) A short error type identifier which can be used
* elsewhere to configure handling of specific types of messages. For
* example, "EXAMPLE1", "EXAMPLE2", etc., where each code identifies a
* class of message like "syntax error", "missing whitespace", etc. This
* allows configuration to later change the severity of all whitespace
* messages, for example.
* - `ignore` (optional) Match some nonempty substring to ignore the match.
* You can use this if your linter sometimes emits text like "No lint
* errors".
* - `stop` (optional) Match some nonempty substring to stop processing input.
* Remaining matches for this file will be discarded, but linting will
* continue with other linters and other files.
* - `halt` (optional) Match some nonempty substring to halt all linting of
* this file by any linter. Linting will continue with other files.
* - `throw` (optional) Match some nonempty substring to throw an error, which
* will stop `arc` completely. You can use this to fail abruptly if you
* encounter unexpected output. All processing will abort.
*
* Numbered capturing groups are ignored.
*
* For example, if your lint script's output looks like this:
*
* error:13 Too many goats!
* warning:22 Not enough boats.
*
* ...you could use this regex to parse it:
*
* /^(?P<severity>warning|error):(?P<line>\d+) (?P<message>.*)$/m
*
* The simplest valid regex for line-oriented output is something like this:
*
* /^(?P<message>.*)$/m
*
* @task lint Linting
* @task linterinfo Linter Information
* @task parse Parsing Output
* @task config Validating Configuration
*/
final class ArcanistScriptAndRegexLinter extends ArcanistLinter {
private $script = null;
private $regex = null;
private $output = array();
public function getInfoName() {
return pht('Script and Regex');
}
public function getInfoDescription() {
return pht(
'Run an external script, then parse its output with a regular '.
'expression. This is a generic binding that can be used to '.
'run custom lint scripts.');
}
/* -( Linting )------------------------------------------------------------ */
/**
* Run the script on each file to be linted.
*
* @task lint
*/
public function willLintPaths(array $paths) {
$root = $this->getProjectRoot();
$futures = array();
foreach ($paths as $path) {
$future = new ExecFuture('%C %s', $this->script, $path);
$future->setCWD($root);
$futures[$path] = $future;
}
$futures = id(new FutureIterator($futures))
->limit(4);
foreach ($futures as $path => $future) {
list($stdout) = $future->resolvex();
$this->output[$path] = $stdout;
}
}
/**
* Run the regex on the output of the script.
*
* @task lint
*/
public function lintPath($path) {
$output = idx($this->output, $path);
if (!strlen($output)) {
// No output, but it exited 0, so just move on.
return;
}
$matches = null;
if (!preg_match_all($this->regex, $output, $matches, PREG_SET_ORDER)) {
// Output with no matches. This might be a configuration error, but more
// likely it's something like "No lint errors." and the user just hasn't
// written a sufficiently powerful/ridiculous regexp to capture it into an
// 'ignore' group. Don't make them figure this out; advanced users can
// capture 'throw' to handle this case.
return;
}
foreach ($matches as $match) {
if (!empty($match['throw'])) {
$throw = $match['throw'];
throw new ArcanistUsageException(
pht(
"%s: configuration captured a '%s' named capturing group, ".
"'%s'. Script output:\n%s",
__CLASS__,
'throw',
$throw,
$output));
}
if (!empty($match['halt'])) {
$this->stopAllLinters();
break;
}
if (!empty($match['stop'])) {
break;
}
if (!empty($match['ignore'])) {
continue;
}
list($line, $char) = $this->getMatchLineAndChar($match, $path);
$dict = array(
'path' => idx($match, 'file', $path),
'line' => $line,
'char' => $char,
'code' => idx($match, 'code', $this->getLinterName()),
'severity' => $this->getMatchSeverity($match),
'name' => idx($match, 'name', 'Lint'),
'description' => idx($match, 'message', pht('Undefined Lint Message')),
);
$original = idx($match, 'original');
if ($original !== null) {
$dict['original'] = $original;
}
$replacement = idx($match, 'replacement');
if ($replacement !== null) {
$dict['replacement'] = $replacement;
}
$lint = ArcanistLintMessage::newFromDictionary($dict);
$this->addLintMessage($lint);
}
}
/* -( Linter Information )------------------------------------------------- */
/**
* Return the short name of the linter.
*
* @return string Short linter identifier.
*
* @task linterinfo
*/
public function getLinterName() {
return 'S&RX';
}
public function getLinterConfigurationName() {
return 'script-and-regex';
}
public function getLinterConfigurationOptions() {
// These fields are optional only to avoid breaking things.
$options = array(
'script-and-regex.script' => array(
'type' => 'string',
'help' => pht('Script to execute.'),
),
'script-and-regex.regex' => array(
'type' => 'regex',
'help' => pht('The regex to process output with.'),
),
);
return $options + parent::getLinterConfigurationOptions();
}
public function setLinterConfigurationValue($key, $value) {
switch ($key) {
case 'script-and-regex.script':
$this->script = $value;
return;
case 'script-and-regex.regex':
$this->regex = $value;
return;
}
return parent::setLinterConfigurationValue($key, $value);
}
/* -( Parsing Output )----------------------------------------------------- */
/**
* Get the line and character of the message from the regex match.
*
* @param dict Captured groups from regex.
* @return pair<int|null,int|null> Line and character of the message.
*
* @task parse
*/
private function getMatchLineAndChar(array $match, $path) {
if (!empty($match['offset'])) {
list($line, $char) = $this->getEngine()->getLineAndCharFromOffset(
idx($match, 'file', $path),
$match['offset']);
return array($line + 1, $char + 1);
}
$line = idx($match, 'line');
if (strlen($line)) {
$line = (int)$line;
if (!$line) {
$line = 1;
}
} else {
$line = null;
}
$char = idx($match, 'char');
if ($char) {
$char = (int)$char;
} else {
$char = null;
}
return array($line, $char);
}
/**
* Map the regex matching groups to a message severity. We look for either
* a nonempty severity name group like 'error', or a group called 'severity'
* with a valid name.
*
* @param dict Captured groups from regex.
* @return const @{class:ArcanistLintSeverity} constant.
*
* @task parse
*/
private function getMatchSeverity(array $match) {
$map = array(
'error' => ArcanistLintSeverity::SEVERITY_ERROR,
'warning' => ArcanistLintSeverity::SEVERITY_WARNING,
'autofix' => ArcanistLintSeverity::SEVERITY_AUTOFIX,
'advice' => ArcanistLintSeverity::SEVERITY_ADVICE,
'disabled' => ArcanistLintSeverity::SEVERITY_DISABLED,
);
$severity_name = strtolower(idx($match, 'severity'));
foreach ($map as $name => $severity) {
if (!empty($match[$name])) {
return $severity;
} else if ($severity_name == $name) {
return $severity;
}
}
return ArcanistLintSeverity::SEVERITY_ERROR;
}
}

View file

@ -1,74 +0,0 @@
<?php
/**
* A linter which uses [[http://php.net/simplexml | SimpleXML]] to detect
* errors and potential problems in XML files.
*/
final class ArcanistXMLLinter extends ArcanistLinter {
public function getInfoName() {
return pht('SimpleXML Linter');
}
public function getInfoDescription() {
return pht('Uses SimpleXML to detect formatting errors in XML files.');
}
public function getLinterName() {
return 'XML';
}
public function getLinterConfigurationName() {
return 'xml';
}
public function canRun() {
return extension_loaded('libxml') && extension_loaded('simplexml');
}
public function getCacheVersion() {
return LIBXML_VERSION;
}
public function lintPath($path) {
libxml_use_internal_errors(true);
libxml_clear_errors();
if (simplexml_load_string($this->getData($path))) {
// XML appears to be valid.
return;
}
foreach (libxml_get_errors() as $error) {
$message = id(new ArcanistLintMessage())
->setPath($path)
->setLine($error->line)
->setChar($error->column ? $error->column : null)
->setCode($this->getLintMessageFullCode($error->code))
->setName(pht('LibXML Error'))
->setDescription(trim($error->message));
switch ($error->level) {
case LIBXML_ERR_NONE:
$message->setSeverity(ArcanistLintSeverity::SEVERITY_DISABLED);
break;
case LIBXML_ERR_WARNING:
$message->setSeverity(ArcanistLintSeverity::SEVERITY_WARNING);
break;
case LIBXML_ERR_ERROR:
case LIBXML_ERR_FATAL:
$message->setSeverity(ArcanistLintSeverity::SEVERITY_ERROR);
break;
default:
$message->setSeverity(ArcanistLintSeverity::SEVERITY_ADVICE);
break;
}
$this->addLintMessage($message);
}
}
}

View file

@ -1,10 +0,0 @@
<?php
final class ArcanistCSSLintLinterTestCase
extends ArcanistExternalLinterTestCase {
public function testLinter() {
$this->executeTestsInDirectory(dirname(__FILE__).'/csslint/');
}
}

View file

@ -1,16 +0,0 @@
<?php
final class ArcanistClosureLinterTestCase
extends ArcanistExternalLinterTestCase {
protected function getLinter() {
$linter = new ArcanistClosureLinter();
$linter->setFlags(array('--additional_extensions=lint-test'));
return $linter;
}
public function testLinter() {
$this->executeTestsInDirectory(dirname(__FILE__).'/gjslint/');
}
}

View file

@ -1,10 +0,0 @@
<?php
final class ArcanistCoffeeLintLinterTestCase
extends ArcanistExternalLinterTestCase {
public function testLinter() {
$this->executeTestsInDirectory(dirname(__FILE__).'/coffeelint/');
}
}

View file

@ -1,10 +0,0 @@
<?php
final class ArcanistCppcheckLinterTestCase
extends ArcanistExternalLinterTestCase {
public function testLinter() {
$this->executeTestsInDirectory(dirname(__FILE__).'/cppcheck/');
}
}

View file

@ -1,10 +0,0 @@
<?php
final class ArcanistCpplintLinterTestCase
extends ArcanistExternalLinterTestCase {
public function testLinter() {
$this->executeTestsInDirectory(dirname(__FILE__).'/cpplint/');
}
}

View file

@ -1,16 +0,0 @@
<?php
abstract class ArcanistExternalLinterTestCase extends ArcanistLinterTestCase {
final public function testVersion() {
try {
$version = $this->getLinter()->getVersion();
$this->assertTrue(
$version !== false,
pht('Failed to parse version from command.'));
} catch (ArcanistMissingLinterException $ex) {
$this->assertSkipped($ex->getMessage());
}
}
}

View file

@ -1,10 +0,0 @@
<?php
final class ArcanistFlake8LinterTestCase
extends ArcanistExternalLinterTestCase {
public function testLinter() {
$this->executeTestsInDirectory(dirname(__FILE__).'/flake8/');
}
}

View file

@ -1,10 +0,0 @@
<?php
final class ArcanistGoLintLinterTestCase
extends ArcanistExternalLinterTestCase {
public function testLinter() {
$this->executeTestsInDirectory(dirname(__FILE__).'/golint/');
}
}

View file

@ -1,9 +0,0 @@
<?php
final class ArcanistHLintLinterTestCase extends ArcanistExternalLinterTestCase {
public function testLinter() {
$this->executeTestsInDirectory(dirname(__FILE__).'/hlint/');
}
}

View file

@ -1,10 +0,0 @@
<?php
final class ArcanistJSHintLinterTestCase
extends ArcanistExternalLinterTestCase {
public function testLinter() {
$this->executeTestsInDirectory(dirname(__FILE__).'/jshint/');
}
}

View file

@ -1,10 +0,0 @@
<?php
final class ArcanistJSONLintLinterTestCase
extends ArcanistExternalLinterTestCase {
public function testLinter() {
$this->executeTestsInDirectory(dirname(__FILE__).'/jsonlint/');
}
}

View file

@ -3,7 +3,7 @@
final class ArcanistJSONLinterTestCase extends ArcanistLinterTestCase {
public function testLinter() {
$this->executeTestsInDirectory(dirname(__FILE__).'/jsonlint/');
$this->executeTestsInDirectory(dirname(__FILE__).'/json/');
}
}

View file

@ -1,9 +0,0 @@
<?php
final class ArcanistJscsLinterTestCase extends ArcanistExternalLinterTestCase {
public function testLinter() {
$this->executeTestsInDirectory(dirname(__FILE__).'/jscs/');
}
}

View file

@ -1,9 +0,0 @@
<?php
final class ArcanistLesscLinterTestCase extends ArcanistExternalLinterTestCase {
public function testLinter() {
$this->executeTestsInDirectory(dirname(__FILE__).'/lessc/');
}
}

View file

@ -1,9 +0,0 @@
<?php
final class ArcanistPEP8LinterTestCase extends ArcanistExternalLinterTestCase {
public function testLinter() {
$this->executeTestsInDirectory(dirname(__FILE__).'/pep8/');
}
}

View file

@ -1,9 +0,0 @@
<?php
final class ArcanistPhpLinterTestCase extends ArcanistExternalLinterTestCase {
public function testLinter() {
$this->executeTestsInDirectory(dirname(__FILE__).'/php/');
}
}

View file

@ -1,9 +0,0 @@
<?php
final class ArcanistPhpcsLinterTestCase extends ArcanistExternalLinterTestCase {
public function testLinter() {
$this->executeTestsInDirectory(dirname(__FILE__).'/phpcs/');
}
}

View file

@ -1,10 +0,0 @@
<?php
final class ArcanistPuppetLintLinterTestCase
extends ArcanistExternalLinterTestCase {
public function testLinter() {
$this->executeTestsInDirectory(dirname(__FILE__).'/puppet-lint/');
}
}

View file

@ -1,10 +0,0 @@
<?php
final class ArcanistPyFlakesLinterTestCase
extends ArcanistExternalLinterTestCase {
public function testLinter() {
$this->executeTestsInDirectory(dirname(__FILE__).'/pyflakes/');
}
}

View file

@ -1,10 +0,0 @@
<?php
final class ArcanistPyLintLinterTestCase
extends ArcanistExternalLinterTestCase {
public function testLinter() {
$this->executeTestsInDirectory(dirname(__FILE__).'/pylint/');
}
}

View file

@ -1,10 +0,0 @@
<?php
final class ArcanistRuboCopLinterTestCase
extends ArcanistExternalLinterTestCase {
public function testLinter() {
$this->executeTestsInDirectory(dirname(__FILE__).'/rubocop/');
}
}

View file

@ -1,9 +0,0 @@
<?php
final class ArcanistRubyLinterTestCase extends ArcanistExternalLinterTestCase {
public function testLinter() {
$this->executeTestsInDirectory(dirname(__FILE__).'/ruby/');
}
}

View file

@ -1,13 +0,0 @@
<?php
/**
* Test cases were mostly taken from
* https://git.gnome.org/browse/libxml2/tree/test.
*/
final class ArcanistXMLLinterTestCase extends ArcanistLinterTestCase {
public function testLinter() {
$this->executeTestsInDirectory(dirname(__FILE__).'/xml/');
}
}

View file

@ -1,3 +0,0 @@
class boaConstrictor
~~~~~~~~~~
error:1:

View file

@ -1,18 +0,0 @@
class SomeThing
getConfig: ->
one = 1
one = 5
@config =
keyA: one
keyB: one
keyA: 2
getConfig: ->
@config =
foo: 1
@getConfig: ->
config =
foo: 1
~~~~~~~~~~
error:8:
error:9:

View file

@ -1,7 +0,0 @@
twoSpaces = () ->
fourSpaces = () ->
eightSpaces = () ->
'this is valid CoffeeScript'
~~~~~~~~~~
error:3:
error:4:

View file

@ -1,3 +0,0 @@
#--------------------------------------------------------------------------------
~~~~~~~~~~
error:1:

View file

@ -1,3 +0,0 @@
`with(document) alert(height);`
~~~~~~~~~~
error:1:

View file

@ -1,3 +0,0 @@
debugger
~~~~~~~~~~
warning:1:

View file

@ -1,6 +0,0 @@
x = () ->
y = () ->
return 1234
~~~~~~~~~~
error:2:
error:3:

View file

@ -1,3 +0,0 @@
throw "i made a boo boo"
~~~~~~~~~~
error:1:

View file

@ -1,3 +0,0 @@
alert('end of line');
~~~~~~~~~~
error:1:

View file

@ -1,4 +0,0 @@
x = 1234
y = 1
~~~~~~~~~~
error:1:

View file

@ -1,9 +0,0 @@
int main()
{
char a[10];
a[10] = 0;
return 0;
}
~~~~~~~~~~
error:4:
warning:4:

View file

@ -1,7 +0,0 @@
void f() {
char arr[5];
// cppcheck-suppress arrayIndexOutOfBounds
// cppcheck-suppress unreadVariable
arr[10] = 0;
}
~~~~~~~~~~

View file

@ -1,5 +0,0 @@
int main()
{
return 0;
}
~~~~~~~~~~

View file

@ -1,19 +0,0 @@
/**
* Taken from http://www.slideshare.net/zblair/cppcheck-10316379
*/
void foo(char* str) {
char* buf = new char[8];
strcpy(buf, str);
FILE* file = fopen("out.txt", "w");
if (!file)
return;
for (char* c = buf; *c; ++c)
fputc((int)*c, file);
delete buf;
}
~~~~~~~~~~
error:10:
error:16:

View file

@ -1,10 +0,0 @@
#include "library.cpp"
#include <stdio>
void main()
{
}
~~~~~~~~~~
warning:0:
warning:2:
warning:5:

View file

@ -1,10 +0,0 @@
.rule {
font-weight: bold;
font-weight: bold;
font-weight: bold;
font-weight: bold;
}
~~~~~~~~~~
warning:3:3
warning:4:3
warning:5:3

View file

@ -1,3 +0,0 @@
.rule { }
~~~~~~~~~~
warning:1:1

View file

@ -1,9 +0,0 @@
h1 {
font-weight: bold;
}
h1 {
font-weight: bold;
}
~~~~~~~~~~
warning::
warning:4:1

View file

@ -1,6 +0,0 @@
li {
float: left;
float left;
}
~~~~~~~~~~
error:3:9

View file

@ -1,7 +0,0 @@
x = 'y'
def hello():
return foo
~~~~~~~~~~
error:3:1
error:4:12

View file

@ -1,20 +0,0 @@
var x = 'some really really really really really really really long string';
var y = 'some really really really really really really really really really long string',
z = 14;
var obj = {name : 'vm'};
var x
var result = true
|| false;
/**
* @param x
* @return {string}
*/
function foo(x) {
return 'bar';
}
~~~~~~~~~~
error:2:
error:4:
error:5:
error:7:
error:9:

View file

@ -1,18 +0,0 @@
package main
import (
"rand"
)
type Exported string
func main() {
if rand.Intn(10) > 5 {
return true
} else {
return false
}
}
~~~~~~~~~~
advice:7:6
advice:12:12

View file

@ -1,3 +0,0 @@
f xs = length xs == 0
~~~~~~~~~~
warning:1:8

View file

@ -1,5 +0,0 @@
f x = x
test x = f x
~~~~~~~~~~
error:3:1

View file

@ -1,2 +0,0 @@
main = map (f . g) xs
~~~~~~~~~~

View file

@ -1,13 +0,0 @@
function foo() {
if (true) return "foo"; else return "bar";
}
~~~~~~~~~~
error:2:3
error:2:27
~~~~~~~~~~
~~~~~~~~~~
{
"config": {
"jscs.preset": "jquery"
}
}

View file

@ -1,6 +0,0 @@
var args = {};
args['foo'] = 'bar';
args['bar'] = 'baz';
~~~~~~~~~~
warning:2:5
warning:3:5

View file

@ -1,6 +0,0 @@
var foo;
if (foo = 'bar') {
return true;
}
~~~~~~~~~~
warning:2:16

View file

@ -1,12 +0,0 @@
function f() {
for (ii = 0; ii < 3; ii++) {
g()
}
}
{
~~~~~~~~~~
warning:3:8
error:7:1
error:9:

View file

@ -1,3 +0,0 @@
console.log('foobar')
~~~~~~~~~~
warning:1:22

View file

@ -1,5 +0,0 @@
/* jshint maxerr: 1 */
console.log('foobar')
~~~~~~~~~~
disabled:2:22
warning:2:22

View file

@ -1,5 +0,0 @@
function main() {
return 'Hello, World!';
};
~~~~~~~~~~
warning:3:2

Some files were not shown because too many files have changed in this diff Show more