diff --git a/resources/bundles/org.eclipse.ui.buildmonitor/.classpath b/resources/bundles/org.eclipse.ui.buildmonitor/.classpath new file mode 100644 index 00000000000..375961e4d61 --- /dev/null +++ b/resources/bundles/org.eclipse.ui.buildmonitor/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/resources/bundles/org.eclipse.ui.buildmonitor/.project b/resources/bundles/org.eclipse.ui.buildmonitor/.project new file mode 100644 index 00000000000..05164c25817 --- /dev/null +++ b/resources/bundles/org.eclipse.ui.buildmonitor/.project @@ -0,0 +1,34 @@ + + + org.eclipse.ui.buildmonitor + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + org.eclipse.pde.api.tools.apiAnalysisBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + org.eclipse.pde.api.tools.apiAnalysisNature + + diff --git a/resources/bundles/org.eclipse.ui.buildmonitor/.settings/org.eclipse.core.resources.prefs b/resources/bundles/org.eclipse.ui.buildmonitor/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 00000000000..99f26c0203a --- /dev/null +++ b/resources/bundles/org.eclipse.ui.buildmonitor/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/resources/bundles/org.eclipse.ui.buildmonitor/.settings/org.eclipse.core.runtime.prefs b/resources/bundles/org.eclipse.ui.buildmonitor/.settings/org.eclipse.core.runtime.prefs new file mode 100644 index 00000000000..5a0ad22d2a7 --- /dev/null +++ b/resources/bundles/org.eclipse.ui.buildmonitor/.settings/org.eclipse.core.runtime.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +line.separator=\n diff --git a/resources/bundles/org.eclipse.ui.buildmonitor/.settings/org.eclipse.jdt.core.prefs b/resources/bundles/org.eclipse.ui.buildmonitor/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000000..70bb1eec7b3 --- /dev/null +++ b/resources/bundles/org.eclipse.ui.buildmonitor/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,141 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.builder.cleanOutputFolder=clean +org.eclipse.jdt.core.builder.duplicateResourceTask=warning +org.eclipse.jdt.core.builder.invalidClasspath=abort +org.eclipse.jdt.core.builder.recreateModifiedClassFileInOutputFolder=ignore +org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.launch +org.eclipse.jdt.core.circularClasspath=error +org.eclipse.jdt.core.classpath.exclusionPatterns=enabled +org.eclipse.jdt.core.classpath.multipleOutputLocations=enabled +org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled +org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore +org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull +org.eclipse.jdt.core.compiler.annotation.nonnull.secondary= +org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault +org.eclipse.jdt.core.compiler.annotation.nonnullbydefault.secondary= +org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable +org.eclipse.jdt.core.compiler.annotation.nullable.secondary= +org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate +org.eclipse.jdt.core.compiler.codegen.targetPlatform=21 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=21 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.doc.comment.support=enabled +org.eclipse.jdt.core.compiler.maxProblemPerUnit=100 +org.eclipse.jdt.core.compiler.problem.APILeak=warning +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.autoboxing=error +org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning +org.eclipse.jdt.core.compiler.problem.deadCode=error +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=error +org.eclipse.jdt.core.compiler.problem.emptyStatement=error +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=warning +org.eclipse.jdt.core.compiler.problem.fallthroughCase=error +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled +org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore +org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning +org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=error +org.eclipse.jdt.core.compiler.problem.forbiddenReference=error +org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=error +org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=error +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning +org.eclipse.jdt.core.compiler.problem.invalidJavadoc=error +org.eclipse.jdt.core.compiler.problem.invalidJavadocTags=enabled +org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=disabled +org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=enabled +org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=protected +org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning +org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled +org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=error +org.eclipse.jdt.core.compiler.problem.missingJavadocComments=ignore +org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=disabled +org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=public +org.eclipse.jdt.core.compiler.problem.missingJavadocTagDescription=return_tag +org.eclipse.jdt.core.compiler.problem.missingJavadocTags=ignore +org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=disabled +org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=protected +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=error +org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore +org.eclipse.jdt.core.compiler.problem.noEffectAssignment=error +org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=error +org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=error +org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning +org.eclipse.jdt.core.compiler.problem.nonnullTypeVariableFromLegacyInvocation=warning +org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error +org.eclipse.jdt.core.compiler.problem.nullReference=error +org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error +org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning +org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore +org.eclipse.jdt.core.compiler.problem.pessimisticNullAnalysisForFreeTypeVariables=warning +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=error +org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore +org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore +org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning +org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore +org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=warning +org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning +org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled +org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=warning +org.eclipse.jdt.core.compiler.problem.terminalDeprecation=warning +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=error +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentType=warning +org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentTypeStrict=disabled +org.eclipse.jdt.core.compiler.problem.unlikelyEqualsArgumentType=info +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled +org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedImport=error +org.eclipse.jdt.core.compiler.problem.unusedLabel=warning +org.eclipse.jdt.core.compiler.problem.unusedLocal=error +org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled +org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=error +org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning +org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=error +org.eclipse.jdt.core.compiler.release=enabled +org.eclipse.jdt.core.compiler.source=21 +org.eclipse.jdt.core.compiler.taskCaseSensitive=enabled +org.eclipse.jdt.core.compiler.taskPriorities=NORMAL,NORMAL +org.eclipse.jdt.core.compiler.taskTags=TODO,XXX +org.eclipse.jdt.core.incompatibleJDKLevel=ignore +org.eclipse.jdt.core.incompleteClasspath=error diff --git a/resources/bundles/org.eclipse.ui.buildmonitor/.settings/org.eclipse.jdt.ui.prefs b/resources/bundles/org.eclipse.ui.buildmonitor/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 00000000000..83308cb79e5 --- /dev/null +++ b/resources/bundles/org.eclipse.ui.buildmonitor/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,151 @@ +eclipse.preferences.version=1 +editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true +internal.default.compliance=user +org.eclipse.jdt.ui.ignorelowercasenames=true +org.eclipse.jdt.ui.importorder=java;javax;org;com; +org.eclipse.jdt.ui.ondemandthreshold=99 +org.eclipse.jdt.ui.staticondemandthreshold=99 +org.eclipse.jdt.ui.text.custom_code_templates= +sp_cleanup.add_all=false +sp_cleanup.add_default_serial_version_id=false +sp_cleanup.add_generated_serial_version_id=false +sp_cleanup.add_missing_annotations=true +sp_cleanup.add_missing_deprecated_annotations=true +sp_cleanup.add_missing_methods=false +sp_cleanup.add_missing_nls_tags=false +sp_cleanup.add_missing_override_annotations=true +sp_cleanup.add_missing_override_annotations_interface_methods=true +sp_cleanup.add_serial_version_id=false +sp_cleanup.also_simplify_lambda=true +sp_cleanup.always_use_blocks=true +sp_cleanup.always_use_parentheses_in_expressions=false +sp_cleanup.always_use_this_for_non_static_field_access=false +sp_cleanup.always_use_this_for_non_static_method_access=false +sp_cleanup.array_with_curly=false +sp_cleanup.arrays_fill=false +sp_cleanup.bitwise_conditional_expression=false +sp_cleanup.boolean_literal=false +sp_cleanup.boolean_value_rather_than_comparison=true +sp_cleanup.break_loop=false +sp_cleanup.collection_cloning=false +sp_cleanup.comparing_on_criteria=false +sp_cleanup.comparison_statement=false +sp_cleanup.controlflow_merge=false +sp_cleanup.convert_functional_interfaces=true +sp_cleanup.convert_to_enhanced_for_loop=true +sp_cleanup.convert_to_enhanced_for_loop_if_loop_var_used=true +sp_cleanup.convert_to_switch_expressions=false +sp_cleanup.correct_indentation=false +sp_cleanup.do_while_rather_than_while=false +sp_cleanup.double_negation=false +sp_cleanup.else_if=false +sp_cleanup.embedded_if=false +sp_cleanup.evaluate_nullable=false +sp_cleanup.extract_increment=false +sp_cleanup.format_source_code=true +sp_cleanup.format_source_code_changes_only=true +sp_cleanup.hash=false +sp_cleanup.if_condition=false +sp_cleanup.insert_inferred_type_arguments=false +sp_cleanup.instanceof=false +sp_cleanup.instanceof_keyword=false +sp_cleanup.invert_equals=false +sp_cleanup.join=false +sp_cleanup.lazy_logical_operator=false +sp_cleanup.make_local_variable_final=true +sp_cleanup.make_parameters_final=false +sp_cleanup.make_private_fields_final=true +sp_cleanup.make_type_abstract_if_missing_method=false +sp_cleanup.make_variable_declarations_final=false +sp_cleanup.map_cloning=false +sp_cleanup.merge_conditional_blocks=false +sp_cleanup.multi_catch=false +sp_cleanup.never_use_blocks=false +sp_cleanup.never_use_parentheses_in_expressions=true +sp_cleanup.no_string_creation=false +sp_cleanup.no_super=false +sp_cleanup.number_suffix=false +sp_cleanup.objects_equals=false +sp_cleanup.on_save_use_additional_actions=true +sp_cleanup.one_if_rather_than_duplicate_blocks_that_fall_through=false +sp_cleanup.operand_factorization=false +sp_cleanup.organize_imports=true +sp_cleanup.overridden_assignment=false +sp_cleanup.overridden_assignment_move_decl=true +sp_cleanup.plain_replacement=false +sp_cleanup.precompile_regex=false +sp_cleanup.primitive_comparison=false +sp_cleanup.primitive_parsing=false +sp_cleanup.primitive_rather_than_wrapper=true +sp_cleanup.primitive_serialization=false +sp_cleanup.pull_out_if_from_if_else=false +sp_cleanup.pull_up_assignment=false +sp_cleanup.push_down_negation=false +sp_cleanup.qualify_static_field_accesses_with_declaring_class=false +sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_with_declaring_class=true +sp_cleanup.qualify_static_method_accesses_with_declaring_class=false +sp_cleanup.reduce_indentation=false +sp_cleanup.redundant_comparator=false +sp_cleanup.redundant_falling_through_block_end=false +sp_cleanup.remove_private_constructors=true +sp_cleanup.remove_redundant_modifiers=false +sp_cleanup.remove_redundant_semicolons=true +sp_cleanup.remove_redundant_type_arguments=true +sp_cleanup.remove_trailing_whitespaces=true +sp_cleanup.remove_trailing_whitespaces_all=true +sp_cleanup.remove_trailing_whitespaces_ignore_empty=false +sp_cleanup.remove_unnecessary_array_creation=false +sp_cleanup.remove_unnecessary_casts=true +sp_cleanup.remove_unnecessary_nls_tags=true +sp_cleanup.remove_unused_imports=true +sp_cleanup.remove_unused_local_variables=false +sp_cleanup.remove_unused_method_parameters=false +sp_cleanup.remove_unused_private_fields=true +sp_cleanup.remove_unused_private_members=false +sp_cleanup.remove_unused_private_methods=true +sp_cleanup.remove_unused_private_types=true +sp_cleanup.replace_deprecated_calls=false +sp_cleanup.return_expression=false +sp_cleanup.simplify_lambda_expression_and_method_ref=true +sp_cleanup.single_used_field=false +sp_cleanup.sort_members=false +sp_cleanup.sort_members_all=false +sp_cleanup.standard_comparison=false +sp_cleanup.static_inner_class=false +sp_cleanup.strictly_equal_or_different=false +sp_cleanup.stringbuffer_to_stringbuilder=false +sp_cleanup.stringbuilder=false +sp_cleanup.stringbuilder_for_local_vars=true +sp_cleanup.stringconcat_stringbuffer_stringbuilder=false +sp_cleanup.stringconcat_to_textblock=false +sp_cleanup.substring=false +sp_cleanup.switch=false +sp_cleanup.system_property=false +sp_cleanup.system_property_boolean=false +sp_cleanup.system_property_file_encoding=false +sp_cleanup.system_property_file_separator=false +sp_cleanup.system_property_line_separator=false +sp_cleanup.system_property_path_separator=false +sp_cleanup.ternary_operator=false +sp_cleanup.try_with_resource=false +sp_cleanup.unlooped_while=false +sp_cleanup.unreachable_block=false +sp_cleanup.use_anonymous_class_creation=false +sp_cleanup.use_autoboxing=false +sp_cleanup.use_blocks=false +sp_cleanup.use_blocks_only_for_return_and_throw=false +sp_cleanup.use_directly_map_method=false +sp_cleanup.use_lambda=true +sp_cleanup.use_parentheses_in_expressions=false +sp_cleanup.use_string_is_blank=false +sp_cleanup.use_this_for_non_static_field_access=false +sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true +sp_cleanup.use_this_for_non_static_method_access=false +sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true +sp_cleanup.use_unboxing=false +sp_cleanup.use_var=false +sp_cleanup.useless_continue=false +sp_cleanup.useless_return=false +sp_cleanup.valueof_rather_than_instantiation=false diff --git a/resources/bundles/org.eclipse.ui.buildmonitor/META-INF/MANIFEST.MF b/resources/bundles/org.eclipse.ui.buildmonitor/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..a42ce3173e2 --- /dev/null +++ b/resources/bundles/org.eclipse.ui.buildmonitor/META-INF/MANIFEST.MF @@ -0,0 +1,15 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %pluginName +Bundle-SymbolicName: org.eclipse.ui.buildmonitor; singleton:=true +Bundle-Version: 1.0.0.qualifier +Bundle-Vendor: %providerName +Bundle-Localization: plugin +Require-Bundle: org.eclipse.ui;bundle-version="[3.208.0,4.0.0)", + org.eclipse.core.runtime;bundle-version="[3.35.0,4.0.0)", + org.eclipse.core.resources;bundle-version="[3.24.0,4.0.0)" +Import-Package: org.eclipse.osgi.service.debug;version="[1.2.0,2.0.0)" +Bundle-ActivationPolicy: lazy +Bundle-RequiredExecutionEnvironment: JavaSE-21 +Export-Package: org.eclipse.ui.internal.buildmonitor;x-internal:=true +Automatic-Module-Name: org.eclipse.ui.buildmonitor diff --git a/resources/bundles/org.eclipse.ui.buildmonitor/about.html b/resources/bundles/org.eclipse.ui.buildmonitor/about.html new file mode 100644 index 00000000000..164f781a8fd --- /dev/null +++ b/resources/bundles/org.eclipse.ui.buildmonitor/about.html @@ -0,0 +1,36 @@ + + + + +About + + +

About This Content

+ +

November 30, 2017

+

License

+ +

+ The Eclipse Foundation makes available all content in this plug-in + ("Content"). Unless otherwise indicated below, the Content + is provided to you under the terms and conditions of the Eclipse + Public License Version 2.0 ("EPL"). A copy of the EPL is + available at http://www.eclipse.org/legal/epl-2.0. + For purposes of the EPL, "Program" will mean the Content. +

+ +

+ If you did not receive this Content directly from the Eclipse + Foundation, the Content is being redistributed by another party + ("Redistributor") and different terms and conditions may + apply to your use of any object code in the Content. Check the + Redistributor's license that was provided with the Content. If no such + license exists, contact the Redistributor. Unless otherwise indicated + below, the terms and conditions of the EPL still apply to any source + code in the Content and such source code may be obtained at http://www.eclipse.org. +

+ + + \ No newline at end of file diff --git a/resources/bundles/org.eclipse.ui.buildmonitor/build.properties b/resources/bundles/org.eclipse.ui.buildmonitor/build.properties new file mode 100644 index 00000000000..1018bbb7434 --- /dev/null +++ b/resources/bundles/org.eclipse.ui.buildmonitor/build.properties @@ -0,0 +1,22 @@ +############################################################################### +# Copyright (c) 2026 Vogella GmbH and others. +# +# This program and the accompanying materials +# are made available under the terms of the Eclipse Public License 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Vogella GmbH - initial API and implementation +############################################################################### +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + icons/,\ + plugin.properties,\ + plugin.xml,\ + about.html +src.includes = about.html diff --git a/resources/bundles/org.eclipse.ui.buildmonitor/icons/full/etool16/build_exec.png b/resources/bundles/org.eclipse.ui.buildmonitor/icons/full/etool16/build_exec.png new file mode 100644 index 00000000000..a8911549e20 Binary files /dev/null and b/resources/bundles/org.eclipse.ui.buildmonitor/icons/full/etool16/build_exec.png differ diff --git a/resources/bundles/org.eclipse.ui.buildmonitor/icons/full/etool16/build_exec.svg b/resources/bundles/org.eclipse.ui.buildmonitor/icons/full/etool16/build_exec.svg new file mode 100644 index 00000000000..4b2bf77dda2 --- /dev/null +++ b/resources/bundles/org.eclipse.ui.buildmonitor/icons/full/etool16/build_exec.svg @@ -0,0 +1,255 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/bundles/org.eclipse.ui.buildmonitor/icons/full/etool16/build_exec@2x.png b/resources/bundles/org.eclipse.ui.buildmonitor/icons/full/etool16/build_exec@2x.png new file mode 100644 index 00000000000..87e738f3243 Binary files /dev/null and b/resources/bundles/org.eclipse.ui.buildmonitor/icons/full/etool16/build_exec@2x.png differ diff --git a/resources/bundles/org.eclipse.ui.buildmonitor/plugin.properties b/resources/bundles/org.eclipse.ui.buildmonitor/plugin.properties new file mode 100644 index 00000000000..74c9b4da915 --- /dev/null +++ b/resources/bundles/org.eclipse.ui.buildmonitor/plugin.properties @@ -0,0 +1,16 @@ +############################################################################### +# Copyright (c) 2026 Vogella GmbH and others. +# +# This program and the accompanying materials +# are made available under the terms of the Eclipse Public License 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Vogella GmbH - initial API and implementation +############################################################################### +pluginName=Build Monitor +providerName=Eclipse.org +BuildMonitorView.name=Build Monitor diff --git a/resources/bundles/org.eclipse.ui.buildmonitor/plugin.xml b/resources/bundles/org.eclipse.ui.buildmonitor/plugin.xml new file mode 100644 index 00000000000..29e67c791da --- /dev/null +++ b/resources/bundles/org.eclipse.ui.buildmonitor/plugin.xml @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/resources/bundles/org.eclipse.ui.buildmonitor/src/org/eclipse/ui/internal/buildmonitor/BuildMonitorView.java b/resources/bundles/org.eclipse.ui.buildmonitor/src/org/eclipse/ui/internal/buildmonitor/BuildMonitorView.java new file mode 100644 index 00000000000..87218b0223b --- /dev/null +++ b/resources/bundles/org.eclipse.ui.buildmonitor/src/org/eclipse/ui/internal/buildmonitor/BuildMonitorView.java @@ -0,0 +1,629 @@ +/******************************************************************************* + * Copyright (c) 2026 Vogella GmbH and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Vogella GmbH - initial API and implementation + *******************************************************************************/ +package org.eclipse.ui.internal.buildmonitor; + +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResourceChangeEvent; +import org.eclipse.core.resources.IResourceChangeListener; +import org.eclipse.core.resources.IncrementalProjectBuilder; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.PerformanceStats; +import org.eclipse.core.runtime.ServiceCaller; +import org.eclipse.jface.action.Action; +import org.eclipse.jface.commands.ActionHandler; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.action.Separator; +import org.eclipse.jface.viewers.ColumnLabelProvider; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.jface.viewers.TreeViewerColumn; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerComparator; +import org.eclipse.osgi.service.debug.DebugOptions; +import org.eclipse.osgi.util.NLS; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.BusyIndicator; +import org.eclipse.swt.dnd.Clipboard; +import org.eclipse.swt.dnd.TextTransfer; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.swt.widgets.TreeColumn; +import org.eclipse.ui.ISharedImages; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.IWorkbenchCommandConstants; +import org.eclipse.ui.actions.ActionFactory; +import org.eclipse.ui.handlers.IHandlerService; +import org.eclipse.ui.part.ViewPart; + +/** + * Shows what each build cost, grouped either by project or by builder. Builder + * tracing is switched on while the view is open and the previous debug options + * are put back when it closes. + */ +public class BuildMonitorView extends ViewPart { + + /** Performance event recorded once per builder run by org.eclipse.core.resources. */ + private static final String EVENT_BUILDERS = "org.eclipse.core.resources/perf/builders"; //$NON-NLS-1$ + + private static final String OPTION_PERF = "org.eclipse.core.runtime/perf"; //$NON-NLS-1$ + private static final String OPTION_PERF_SUCCESS = "org.eclipse.core.runtime/perf/success"; //$NON-NLS-1$ + + /** + * The options this view turns on, global flag first. A builder threshold of 0 + * records every run without writing any of them to the performance log, and + * perf/success is off because only the per-project counters are read. + */ + private static final List OPTION_ORDER = List.of(OPTION_PERF, OPTION_PERF_SUCCESS, EVENT_BUILDERS); + private static final Map OPTION_VALUES = Map.of(OPTION_PERF, "true", //$NON-NLS-1$ + OPTION_PERF_SUCCESS, "false", //$NON-NLS-1$ + EVENT_BUILDERS, "0"); //$NON-NLS-1$ + + /** + * Bounds on what is kept. One build of a large workspace is thousands of rows + * and one of a single project is a handful, so the row budget is what actually + * bounds the memory and the build count only keeps the top level readable. + */ + private static final int MAX_BUILDS = 25; + private static final int MAX_ROWS = 50_000; + + private static final DateTimeFormatter TIME = DateTimeFormatter.ofPattern("HH:mm:ss"); //$NON-NLS-1$ + + private static final int COLUMN_NAME = 0; + private static final int COLUMN_RUNS = 1; + private static final int COLUMN_TIME = 2; + private static final int COLUMN_SHARE = 3; + private static final int COLUMN_WALL = 4; + + private final List builds = new ArrayList<>(); + private final Map replacedOptions = new LinkedHashMap<>(); + private boolean tracing; + private boolean debugWasEnabled; + private boolean groupedByBuilder; + + private TreeViewer viewer; + private TreeColumn nameColumn; + private final BuildComparator comparator = new BuildComparator(); + + /** Counters at the moment the running build started, null while none runs. */ + private Map buildStartCounters; + private long buildStartNanos; + private String buildLabel; + private LocalTime buildStarted; + private int buildDepth; + + private final IResourceChangeListener buildListener = event -> { + if (event.getType() == IResourceChangeEvent.PRE_BUILD) { + buildStarted(event); + } else { + buildFinished(); + } + }; + + @Override + public void createPartControl(Composite parent) { + viewer = new TreeViewer(parent, SWT.FULL_SELECTION | SWT.H_SCROLL | SWT.V_SCROLL); + Tree tree = viewer.getTree(); + tree.setHeaderVisible(true); + tree.setLinesVisible(true); + + nameColumn = addColumn(columnHeader(), null, 420, SWT.LEFT, COLUMN_NAME, this::name); + addColumn(Messages.BuildMonitorView_runs_column, Messages.BuildMonitorView_runs_column_tooltip, 70, SWT.RIGHT, + COLUMN_RUNS, this::runs); + addColumn(Messages.BuildMonitorView_time_column, Messages.BuildMonitorView_time_column_tooltip, 130, SWT.RIGHT, + COLUMN_TIME, this::time); + addColumn(Messages.BuildMonitorView_share_column, Messages.BuildMonitorView_share_column_tooltip, 80, SWT.RIGHT, + COLUMN_SHARE, this::share); + addColumn(Messages.BuildMonitorView_wall_column, Messages.BuildMonitorView_wall_column_tooltip, 160, SWT.RIGHT, + COLUMN_WALL, this::wall); + + viewer.setContentProvider(new BuildContentProvider()); + viewer.setComparator(comparator); + viewer.setInput(builds); + + createContextMenu(); + createToolBar(); + + tracing = enableTracing(); + if (tracing) { + ResourcesPlugin.getWorkspace().addResourceChangeListener(buildListener, + IResourceChangeEvent.PRE_BUILD | IResourceChangeEvent.POST_BUILD); + } + updateDescription(); + } + + private void createToolBar() { + IToolBarManager toolBar = getViewSite().getActionBars().getToolBarManager(); + + Action byBuilder = new Action(Messages.BuildMonitorView_by_builder_action, IAction.AS_CHECK_BOX) { + @Override + public void run() { + groupedByBuilder = isChecked(); + nameColumn.setText(columnHeader()); + withoutRedraw(viewer::refresh); + } + }; + byBuilder.setToolTipText(Messages.BuildMonitorView_by_builder_action_tooltip); + toolBar.add(byBuilder); + // also in the view menu, where Eclipse puts a grouping switch + getViewSite().getActionBars().getMenuManager().add(byBuilder); + getViewSite().getActionBars().getMenuManager().add(copyAction()); + toolBar.add(new Separator()); + toolBar.add(action(Messages.BuildMonitorView_expand_all_action, Messages.BuildMonitorView_expand_all_action, + ISharedImages.IMG_ELCL_EXPANDALL, () -> withoutRedraw(viewer::expandAll))); + toolBar.add(action(Messages.BuildMonitorView_collapse_all_action, Messages.BuildMonitorView_collapse_all_action, + ISharedImages.IMG_ELCL_COLLAPSEALL, () -> withoutRedraw(viewer::collapseAll))); + toolBar.add(new Separator()); + toolBar.add(action(Messages.BuildMonitorView_clear_action, Messages.BuildMonitorView_clear_action_tooltip, + ISharedImages.IMG_ETOOL_CLEAR, () -> { + builds.clear(); + viewer.refresh(); + updateDescription(); + })); + } + + @Override + public void dispose() { + ResourcesPlugin.getWorkspace().removeResourceChangeListener(buildListener); + disableTracing(); + super.dispose(); + } + + @Override + public void setFocus() { + viewer.getControl().setFocus(); + } + + private void createContextMenu() { + Action copy = copyAction(); + MenuManager menuManager = new MenuManager(); + menuManager.add(copy); + Menu menu = menuManager.createContextMenu(viewer.getTree()); + viewer.getTree().setMenu(menu); + + // Ctrl+C while the tree has focus. The retargetable action alone is not + // enough, the copy command is answered by another handler otherwise. + getViewSite().getActionBars().setGlobalActionHandler(ActionFactory.COPY.getId(), copy); + getViewSite().getActionBars().updateActionBars(); + IHandlerService handlers = getSite().getService(IHandlerService.class); + if (handlers != null) { + handlers.activateHandler(IWorkbenchCommandConstants.EDIT_COPY, new ActionHandler(copy)); + } + } + + private Action copyAction() { + Action copy = new Action(Messages.BuildMonitorView_copy_action) { + @Override + public void run() { + copyToClipboard(); + } + }; + copy.setToolTipText(Messages.BuildMonitorView_copy_action_tooltip); + return copy; + } + + /** Copies the selected rows, or everything when nothing is selected. */ + private void copyToClipboard() { + List rows = new ArrayList<>(); + if (viewer.getSelection() instanceof IStructuredSelection selection && !selection.isEmpty()) { + selection.forEach(rows::add); + } else { + for (BuildRun build : builds) { + rows.add(build); + for (GroupEntry group : build.getGroups(groupedByBuilder)) { + rows.add(group); + rows.addAll(group.getChildren()); + } + } + } + if (rows.isEmpty()) { + return; + } + StringBuilder text = new StringBuilder(Messages.BuildMonitorView_copy_header); + rows.forEach(row -> appendRow(text, row)); + Clipboard clipboard = new Clipboard(viewer.getTree().getDisplay()); + try { + clipboard.setContents(new Object[] { text.toString() }, + new Transfer[] { TextTransfer.getInstance() }); + } finally { + clipboard.dispose(); + } + } + + /** + * One tab separated line per row. Every row carries its build, project and + * builder, so a line stays meaningful once it is out of the tree. + */ + private void appendRow(StringBuilder text, Object element) { + String build = ""; //$NON-NLS-1$ + String started = ""; //$NON-NLS-1$ + String project = ""; //$NON-NLS-1$ + String builder = ""; //$NON-NLS-1$ + if (element instanceof BuildRun run) { + build = run.getLabel(); + started = TIME.format(run.getStarted()); + } else if (element instanceof GroupEntry group) { + if (group.isGroupedByBuilder()) { + builder = group.getName(); + } else { + project = group.getName(); + } + } else if (element instanceof BuilderEntry leaf) { + project = leaf.getProject(); + builder = BuilderLabels.of(leaf.getBuilder()); + } + text.append(System.lineSeparator()); + text.append(clean(build)).append('\t').append(started).append('\t'); + text.append(clean(project)).append('\t').append(clean(builder)).append('\t'); + text.append(runsOf(element)).append('\t').append(timeOf(element)).append('\t'); + text.append(String.format("%.1f", Double.valueOf(shareOf(element)))).append('\t'); //$NON-NLS-1$ + text.append(element instanceof BuildRun run ? Long.toString(run.getWallTime()) : ""); //$NON-NLS-1$ + } + + private static String clean(String value) { + return value.replace('\t', ' ').replace('\n', ' '); + } + + private String columnHeader() { + return groupedByBuilder ? Messages.BuildMonitorView_builder_column : Messages.BuildMonitorView_project_column; + } + + private static Action action(String text, String tooltip, String sharedImage, Runnable body) { + Action action = new Action(text) { + @Override + public void run() { + body.run(); + } + }; + action.setToolTipText(tooltip); + action.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(sharedImage)); + return action; + } + + /** + * Expanding a build of a large workspace creates thousands of rows, so the tree + * is only painted once the whole operation is done. + */ + private void withoutRedraw(Runnable body) { + Tree tree = viewer.getTree(); + tree.setRedraw(false); + try { + BusyIndicator.showWhile(tree.getDisplay(), body); + } finally { + tree.setRedraw(true); + } + } + + private TreeColumn addColumn(String header, String tooltip, int width, int alignment, int index, + Function text) { + TreeViewerColumn column = new TreeViewerColumn(viewer, alignment); + TreeColumn treeColumn = column.getColumn(); + treeColumn.setText(header); + treeColumn.setToolTipText(tooltip); + treeColumn.setWidth(width); + treeColumn.addListener(SWT.Selection, e -> sortBy(index, treeColumn)); + column.setLabelProvider(new ColumnLabelProvider() { + @Override + public String getText(Object element) { + return text.apply(element); + } + }); + return treeColumn; + } + + /** Clicking the sorted column flips the direction, another column starts at descending. */ + private void sortBy(int column, TreeColumn treeColumn) { + if (comparator.column == column) { + comparator.ascending = !comparator.ascending; + } else { + comparator.column = column; + comparator.ascending = column == COLUMN_NAME; + } + Tree tree = viewer.getTree(); + tree.setSortColumn(treeColumn); + tree.setSortDirection(comparator.ascending ? SWT.UP : SWT.DOWN); + withoutRedraw(viewer::refresh); + } + + private String name(Object element) { + if (element instanceof BuildRun build) { + String pattern = build.getProjects() == 1 ? Messages.BuildMonitorView_build_label_one + : Messages.BuildMonitorView_build_label; + return NLS.bind(pattern, new Object[] { build.getLabel(), TIME.format(build.getStarted()), + Integer.valueOf(build.getProjects()) }); + } + if (element instanceof GroupEntry group) { + return group.getName(); + } + return ((BuilderEntry) element).getLabel(groupedByBuilder); + } + + private String runs(Object element) { + return Integer.toString(runsOf(element)); + } + + private String time(Object element) { + return Long.toString(timeOf(element)); + } + + /** + * On a build, how much of it was builders at all; below it, the row's share of + * that build's builder time. + */ + private String share(Object element) { + return String.format("%.1f%%", Double.valueOf(shareOf(element))); //$NON-NLS-1$ + } + + private static double shareOf(Object element) { + if (element instanceof BuildRun build) { + return build.getShare(); + } + if (element instanceof GroupEntry group) { + return group.getShare(); + } + return ((BuilderEntry) element).getShare(); + } + + /** Only a build has a wall time; below it the builder times are the whole story. */ + private String wall(Object element) { + return element instanceof BuildRun build ? Long.toString(build.getWallTime()) : ""; //$NON-NLS-1$ + } + + private static int runsOf(Object element) { + if (element instanceof BuildRun build) { + return build.getRuns(); + } + if (element instanceof GroupEntry group) { + return group.getRuns(); + } + return ((BuilderEntry) element).getRuns(); + } + + private static long timeOf(Object element) { + if (element instanceof BuildRun build) { + return build.getTime(); + } + if (element instanceof GroupEntry group) { + return group.getTime(); + } + return ((BuilderEntry) element).getTime(); + } + + private void buildStarted(IResourceChangeEvent event) { + if (buildDepth++ > 0) { + // a builder that builds another project nests, and the outer build owns the time + return; + } + buildStartCounters = counters(); + buildStartNanos = System.nanoTime(); + buildStarted = LocalTime.now(); + buildLabel = label(event); + } + + private void buildFinished() { + if (buildDepth > 0) { + buildDepth--; + } + if (buildDepth > 0 || buildStartCounters == null) { + return; + } + long wallTime = (System.nanoTime() - buildStartNanos) / 1_000_000L; + List leaves = since(buildStartCounters); + buildStartCounters = null; + if (leaves.isEmpty()) { + // a build that ran no builder at all is noise rather than a measurement + return; + } + BuildRun build = new BuildRun(buildLabel, buildStarted, wallTime, leaves); + Tree tree = viewer.getTree(); + if (tree.isDisposed()) { + return; + } + tree.getDisplay().asyncExec(() -> add(build)); + } + + private void add(BuildRun build) { + if (viewer.getTree().isDisposed()) { + return; + } + builds.add(0, build); + trim(); + viewer.refresh(); + viewer.expandToLevel(build, 1); + viewer.reveal(build); + updateDescription(); + } + + /** Drops the oldest builds until both bounds hold, always keeping the newest. */ + private void trim() { + int rows = 0; + for (BuildRun build : builds) { + rows += build.getLeafCount(); + } + while (builds.size() > 1 && (builds.size() > MAX_BUILDS || rows > MAX_ROWS)) { + rows -= builds.remove(builds.size() - 1).getLeafCount(); + } + } + + /** + * The accumulated builder counters, keyed by builder and project. + * {@link PerformanceStats} updates these while the builder returns, so they are + * complete by the time the build ends, unlike the batched listener callbacks. + */ + private static Map counters() { + Map counters = new HashMap<>(); + for (PerformanceStats stats : PerformanceStats.getAllStats()) { + if (EVENT_BUILDERS.equals(stats.getEvent()) && stats.getContext() != null) { + counters.put(new Key(stats.getBlameString(), stats.getContext()), + new long[] { stats.getRunCount(), stats.getRunningTime() }); + } + } + return counters; + } + + /** What the counters gained since the given snapshot. */ + private static List since(Map before) { + List leaves = new ArrayList<>(); + counters().forEach((key, now) -> { + long[] then = before.getOrDefault(key, new long[] { 0, 0 }); + int runs = (int) (now[0] - then[0]); + if (runs > 0) { + leaves.add(new BuilderEntry(key.builder(), key.project(), runs, Math.max(now[1] - then[1], 0))); + } + }); + return leaves; + } + + /** + * A builder on a project. The two strings belong to the shared + * {@link PerformanceStats} objects, so every recorded build refers to the same + * names rather than to copies of them. + */ + private record Key(String builder, String project) { + } + + private static String label(IResourceChangeEvent event) { + String kind = switch (event.getBuildKind()) { + case IncrementalProjectBuilder.FULL_BUILD -> Messages.BuildMonitorView_kind_full; + case IncrementalProjectBuilder.CLEAN_BUILD -> Messages.BuildMonitorView_kind_clean; + case IncrementalProjectBuilder.AUTO_BUILD -> Messages.BuildMonitorView_kind_auto; + default -> Messages.BuildMonitorView_kind_incremental; + }; + if (event.getSource() instanceof IProject project) { + return NLS.bind(Messages.BuildMonitorView_scope_project, kind, project.getName()); + } + return NLS.bind(Messages.BuildMonitorView_scope_workspace, kind); + } + + private void updateDescription() { + if (!tracing) { + setContentDescription(Messages.BuildMonitorView_tracing_unavailable); + } else if (builds.isEmpty()) { + setContentDescription(Messages.BuildMonitorView_waiting); + } else { + setContentDescription(NLS.bind(Messages.BuildMonitorView_recorded, Integer.valueOf(builds.size()))); + } + } + + /** + * Turns builder tracing on, remembering the previous state so that + * {@link #disableTracing()} can put it back. Returns whether the debug options + * service was available. + */ + private boolean enableTracing() { + return ServiceCaller.callOnce(getClass(), DebugOptions.class, options -> { + debugWasEnabled = options.isDebugEnabled(); + for (String option : OPTION_ORDER) { + replacedOptions.put(option, options.getOption(option)); + } + options.setDebugEnabled(true); + for (String option : OPTION_ORDER) { + options.setOption(option, OPTION_VALUES.get(option)); + } + }); + } + + private void disableTracing() { + if (!tracing) { + // nothing was changed, so there is nothing to put back + return; + } + tracing = false; + ServiceCaller.callOnce(getClass(), DebugOptions.class, options -> { + // Put the options back before disabling. Equinox stashes whatever is set when + // debugging goes off and hands it out again the next time it goes on, so + // leaving ours in place would resurrect them. + replacedOptions.forEach((option, value) -> { + if (value == null) { + options.removeOption(option); + } else { + options.setOption(option, value); + } + }); + if (!debugWasEnabled) { + options.setDebugEnabled(false); + } + }); + } + + /** + * Sorts by the column whose header was clicked. Without a chosen column the + * builds stay newest first and everything below them slowest first. + */ + private final class BuildComparator extends ViewerComparator { + + private int column = -1; + private boolean ascending; + + @Override + public int compare(Viewer v, Object e1, Object e2) { + if (column < 0) { + return e1 instanceof BuildRun ? 0 : Long.compare(timeOf(e2), timeOf(e1)); + } + int result = switch (column) { + case COLUMN_RUNS -> Integer.compare(runsOf(e1), runsOf(e2)); + case COLUMN_TIME -> Long.compare(timeOf(e1), timeOf(e2)); + case COLUMN_SHARE -> Double.compare(shareOf(e1), shareOf(e2)); + case COLUMN_WALL -> Long.compare(wallOf(e1), wallOf(e2)); + default -> name(e1).compareToIgnoreCase(name(e2)); + }; + return ascending ? result : -result; + } + + private long wallOf(Object element) { + return element instanceof BuildRun build ? build.getWallTime() : 0; + } + } + + private final class BuildContentProvider implements ITreeContentProvider { + + @Override + public Object[] getElements(Object input) { + return ((List) input).toArray(); + } + + @Override + public Object[] getChildren(Object element) { + if (element instanceof BuildRun build) { + return build.getGroups(groupedByBuilder).toArray(); + } + if (element instanceof GroupEntry group) { + return group.getChildren().toArray(); + } + return new Object[0]; + } + + @Override + public boolean hasChildren(Object element) { + return element instanceof BuildRun || element instanceof GroupEntry; + } + + @Override + public Object getParent(Object element) { + return null; + } + } +} diff --git a/resources/bundles/org.eclipse.ui.buildmonitor/src/org/eclipse/ui/internal/buildmonitor/BuildRun.java b/resources/bundles/org.eclipse.ui.buildmonitor/src/org/eclipse/ui/internal/buildmonitor/BuildRun.java new file mode 100644 index 00000000000..11f41295b1c --- /dev/null +++ b/resources/bundles/org.eclipse.ui.buildmonitor/src/org/eclipse/ui/internal/buildmonitor/BuildRun.java @@ -0,0 +1,109 @@ +/******************************************************************************* + * Copyright (c) 2026 Vogella GmbH and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Vogella GmbH - initial API and implementation + *******************************************************************************/ +package org.eclipse.ui.internal.buildmonitor; + +import java.time.LocalTime; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * One build invocation, with the time each builder spent on each project in it. + * The same leaves are grouped either by project or by builder. + */ +class BuildRun { + + private final String label; + private final LocalTime started; + private final long wallTime; + private final List leaves; + private final long builderTime; + private final int runs; + private final int projects; + + private List byProject; + private List byBuilder; + + BuildRun(String label, LocalTime started, long wallTime, List leaves) { + this.label = label; + this.started = started; + this.wallTime = wallTime; + this.leaves = leaves; + this.builderTime = leaves.stream().mapToLong(BuilderEntry::getTime).sum(); + this.runs = leaves.stream().mapToInt(BuilderEntry::getRuns).sum(); + this.projects = (int) leaves.stream().map(BuilderEntry::getProject).distinct().count(); + leaves.forEach(leaf -> leaf.setBuildTotal(builderTime)); + } + + /** How many projects actually ran a builder in this build. */ + int getProjects() { + return projects; + } + + /** How much of the build was spent inside builders rather than around them. */ + double getShare() { + return wallTime > 0 ? 100.0 * builderTime / wallTime : 0; + } + + String getLabel() { + return label; + } + + LocalTime getStarted() { + return started; + } + + /** Time from the start of the build until every builder has finished. */ + long getWallTime() { + return wallTime; + } + + /** Time spent inside builders, which is at most {@link #getWallTime()}. */ + long getTime() { + return builderTime; + } + + int getRuns() { + return runs; + } + + /** How many rows this build contributes to the tree once fully expanded. */ + int getLeafCount() { + return leaves.size(); + } + + synchronized List getGroups(boolean groupedByBuilder) { + if (groupedByBuilder) { + if (byBuilder == null) { + byBuilder = group(true); + } + return byBuilder; + } + if (byProject == null) { + byProject = group(false); + } + return byProject; + } + + private List group(boolean groupedByBuilder) { + Map> children = new LinkedHashMap<>(); + for (BuilderEntry leaf : leaves) { + children.computeIfAbsent(leaf.getGroup(groupedByBuilder), name -> new ArrayList<>()).add(leaf); + } + List groups = new ArrayList<>(); + children.forEach((name, entries) -> groups.add(new GroupEntry(name, entries, groupedByBuilder, builderTime))); + return groups; + } +} diff --git a/resources/bundles/org.eclipse.ui.buildmonitor/src/org/eclipse/ui/internal/buildmonitor/BuilderEntry.java b/resources/bundles/org.eclipse.ui.buildmonitor/src/org/eclipse/ui/internal/buildmonitor/BuilderEntry.java new file mode 100644 index 00000000000..9ff90a59726 --- /dev/null +++ b/resources/bundles/org.eclipse.ui.buildmonitor/src/org/eclipse/ui/internal/buildmonitor/BuilderEntry.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2026 Vogella GmbH and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Vogella GmbH - initial API and implementation + *******************************************************************************/ +package org.eclipse.ui.internal.buildmonitor; + +/** + * What one builder cost on one project in one build. This is the leaf of the + * tree either way round, so it carries both names and the grouping decides + * which of them is shown. + */ +class BuilderEntry { + + private final String builder; + private final String project; + private final int runs; + private final long time; + private long buildTotal; + + BuilderEntry(String builder, String project, int runs, long time) { + this.builder = builder; + this.project = project; + this.runs = runs; + this.time = time; + } + + /** The builder class name, which is what the performance event blames. */ + String getBuilder() { + return builder; + } + + String getProject() { + return project; + } + + int getRuns() { + return runs; + } + + long getTime() { + return time; + } + + /** Set once by the enclosing build, which only knows its total after all leaves exist. */ + void setBuildTotal(long buildTotal) { + this.buildTotal = buildTotal; + } + + /** This leaf's percentage of the builder time of its build. */ + double getShare() { + return buildTotal > 0 ? 100.0 * time / buildTotal : 0; + } + + /** The name of the dimension the enclosing group does not already show. */ + String getLabel(boolean groupedByBuilder) { + return groupedByBuilder ? project : BuilderLabels.of(builder); + } + + String getGroup(boolean groupedByBuilder) { + return groupedByBuilder ? BuilderLabels.of(builder) : project; + } +} diff --git a/resources/bundles/org.eclipse.ui.buildmonitor/src/org/eclipse/ui/internal/buildmonitor/BuilderLabels.java b/resources/bundles/org.eclipse.ui.buildmonitor/src/org/eclipse/ui/internal/buildmonitor/BuilderLabels.java new file mode 100644 index 00000000000..a386bcecb6c --- /dev/null +++ b/resources/bundles/org.eclipse.ui.buildmonitor/src/org/eclipse/ui/internal/buildmonitor/BuilderLabels.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * Copyright (c) 2026 Vogella GmbH and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Vogella GmbH - initial API and implementation + *******************************************************************************/ +package org.eclipse.ui.internal.buildmonitor; + +import java.util.HashMap; +import java.util.Map; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExtension; +import org.eclipse.core.runtime.IExtensionPoint; +import org.eclipse.core.runtime.Platform; + +/** + * Maps a builder class name to the name its extension declares, so the tree can + * show "Java Builder" rather than the implementation class. + */ +final class BuilderLabels { + + private static Map namesByClass; + + private BuilderLabels() { + // Do not instantiate. + } + + /** The declared name of the builder, or the class name when there is none. */ + static synchronized String of(String builderClass) { + if (namesByClass == null) { + namesByClass = read(); + } + return namesByClass.getOrDefault(builderClass, builderClass); + } + + private static Map read() { + Map names = new HashMap<>(); + IExtensionPoint point = Platform.getExtensionRegistry() + .getExtensionPoint(ResourcesPlugin.PI_RESOURCES, ResourcesPlugin.PT_BUILDERS); + if (point == null) { + return names; + } + for (IExtension extension : point.getExtensions()) { + String name = extension.getLabel(); + if (name == null || name.isBlank()) { + continue; + } + for (IConfigurationElement element : extension.getConfigurationElements()) { + collectRunClasses(element, name, names); + } + } + return names; + } + + private static void collectRunClasses(IConfigurationElement element, String name, Map names) { + if ("run".equals(element.getName())) { //$NON-NLS-1$ + String className = element.getAttribute("class"); //$NON-NLS-1$ + if (className != null) { + names.putIfAbsent(className, name); + } + return; + } + for (IConfigurationElement child : element.getChildren()) { + collectRunClasses(child, name, names); + } + } +} diff --git a/resources/bundles/org.eclipse.ui.buildmonitor/src/org/eclipse/ui/internal/buildmonitor/GroupEntry.java b/resources/bundles/org.eclipse.ui.buildmonitor/src/org/eclipse/ui/internal/buildmonitor/GroupEntry.java new file mode 100644 index 00000000000..12a775ba555 --- /dev/null +++ b/resources/bundles/org.eclipse.ui.buildmonitor/src/org/eclipse/ui/internal/buildmonitor/GroupEntry.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2026 Vogella GmbH and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Vogella GmbH - initial API and implementation + *******************************************************************************/ +package org.eclipse.ui.internal.buildmonitor; + +import java.util.List; + +/** + * The middle level of the tree: one project with its builders below it, or one + * builder with its projects below it, depending on the grouping. + */ +class GroupEntry { + + private final String name; + private final List children; + private final boolean groupedByBuilder; + private final long time; + private final int runs; + private final long buildTotal; + + GroupEntry(String name, List children, boolean groupedByBuilder, long buildTotal) { + this.name = name; + this.children = children; + this.groupedByBuilder = groupedByBuilder; + this.buildTotal = buildTotal; + this.time = children.stream().mapToLong(BuilderEntry::getTime).sum(); + this.runs = children.stream().mapToInt(BuilderEntry::getRuns).sum(); + } + + /** This group's percentage of the builder time of its build. */ + double getShare() { + return buildTotal > 0 ? 100.0 * time / buildTotal : 0; + } + + String getName() { + return name; + } + + boolean isGroupedByBuilder() { + return groupedByBuilder; + } + + long getTime() { + return time; + } + + int getRuns() { + return runs; + } + + List getChildren() { + return children; + } +} diff --git a/resources/bundles/org.eclipse.ui.buildmonitor/src/org/eclipse/ui/internal/buildmonitor/Messages.java b/resources/bundles/org.eclipse.ui.buildmonitor/src/org/eclipse/ui/internal/buildmonitor/Messages.java new file mode 100644 index 00000000000..4f3d81df9ae --- /dev/null +++ b/resources/bundles/org.eclipse.ui.buildmonitor/src/org/eclipse/ui/internal/buildmonitor/Messages.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2026 Vogella GmbH and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Vogella GmbH - initial API and implementation + *******************************************************************************/ +package org.eclipse.ui.internal.buildmonitor; + +import org.eclipse.osgi.util.NLS; + +final class Messages extends NLS { + public static String BuildMonitorView_build_label; + public static String BuildMonitorView_build_label_one; + public static String BuildMonitorView_builder_column; + public static String BuildMonitorView_by_builder_action; + public static String BuildMonitorView_by_builder_action_tooltip; + public static String BuildMonitorView_clear_action; + public static String BuildMonitorView_copy_action; + public static String BuildMonitorView_copy_action_tooltip; + public static String BuildMonitorView_copy_header; + public static String BuildMonitorView_clear_action_tooltip; + public static String BuildMonitorView_collapse_all_action; + public static String BuildMonitorView_expand_all_action; + public static String BuildMonitorView_kind_auto; + public static String BuildMonitorView_kind_clean; + public static String BuildMonitorView_kind_full; + public static String BuildMonitorView_kind_incremental; + public static String BuildMonitorView_project_column; + public static String BuildMonitorView_recorded; + public static String BuildMonitorView_runs_column; + public static String BuildMonitorView_share_column; + public static String BuildMonitorView_share_column_tooltip; + public static String BuildMonitorView_runs_column_tooltip; + public static String BuildMonitorView_scope_project; + public static String BuildMonitorView_scope_workspace; + public static String BuildMonitorView_time_column; + public static String BuildMonitorView_time_column_tooltip; + public static String BuildMonitorView_tracing_unavailable; + public static String BuildMonitorView_waiting; + public static String BuildMonitorView_wall_column; + public static String BuildMonitorView_wall_column_tooltip; + + private Messages() { + // Do not instantiate. + } + + static { + NLS.initializeMessages(Messages.class.getName(), Messages.class); + } +} diff --git a/resources/bundles/org.eclipse.ui.buildmonitor/src/org/eclipse/ui/internal/buildmonitor/Messages.properties b/resources/bundles/org.eclipse.ui.buildmonitor/src/org/eclipse/ui/internal/buildmonitor/Messages.properties new file mode 100644 index 00000000000..802ed427f4c --- /dev/null +++ b/resources/bundles/org.eclipse.ui.buildmonitor/src/org/eclipse/ui/internal/buildmonitor/Messages.properties @@ -0,0 +1,44 @@ +############################################################################### +# Copyright (c) 2026 Vogella GmbH and others. +# +# This program and the accompanying materials +# are made available under the terms of the Eclipse Public License 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Vogella GmbH - initial API and implementation +############################################################################### + +BuildMonitorView_build_label={0} at {1} for {2} projects +BuildMonitorView_build_label_one={0} at {1} for 1 project +BuildMonitorView_builder_column=Build / Builder / Project +BuildMonitorView_by_builder_action=By builder +BuildMonitorView_by_builder_action_tooltip=Group each build by builder instead of by project +BuildMonitorView_clear_action=Clear +BuildMonitorView_copy_action=Copy +BuildMonitorView_copy_action_tooltip=Copies the selected rows, or all of them, as tab separated text +BuildMonitorView_copy_header=Build\tStarted\tProject\tBuilder\tRuns\tBuilder Time (ms)\tShare (%)\tTotal Build Time (ms) +BuildMonitorView_clear_action_tooltip=Discards the recorded builds +BuildMonitorView_collapse_all_action=Collapse All +BuildMonitorView_expand_all_action=Expand All +BuildMonitorView_kind_auto=Auto build +BuildMonitorView_kind_clean=Clean +BuildMonitorView_kind_full=Full build +BuildMonitorView_kind_incremental=Incremental build +BuildMonitorView_project_column=Build / Project / Builder +BuildMonitorView_recorded={0} builds recorded, newest first. +BuildMonitorView_runs_column=Runs +BuildMonitorView_share_column=Share +BuildMonitorView_share_column_tooltip=Share of this build's builder time; on a build row, how much of the build was builders at all +BuildMonitorView_runs_column_tooltip=How often a builder was invoked +BuildMonitorView_scope_project={0} of {1} +BuildMonitorView_scope_workspace={0} of the workspace +BuildMonitorView_time_column=Builder Time (ms) +BuildMonitorView_time_column_tooltip=Time spent inside the builders themselves +BuildMonitorView_tracing_unavailable=Tracing is unavailable, the debug options service was not found. +BuildMonitorView_waiting=Builder tracing is on. Run a build to see where its time goes. +BuildMonitorView_wall_column=Total Build Time (ms) +BuildMonitorView_wall_column_tooltip=Time the whole build took, including the work around the builders