diff options
author | 2017-08-10 12:29:25 +0200 | |
---|---|---|
committer | 2017-08-10 13:48:24 +0200 | |
commit | 9220eec3c8359907284edd78191467b6df7ae4d0 (patch) | |
tree | 708e5137e89439b413b516cd2d6aea4cb3158a09 /src/main/java/com/google/devtools/build/lib/rules/extra | |
parent | 3a5002f119fe1d37d897445f21f3ad650caf83c6 (diff) |
Move extra action stuff to analysis.extra
This is part of splitting up the build-base library into separate libraries for
analysis, exec, and rules.
PiperOrigin-RevId: 164835678
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/rules/extra')
6 files changed, 3 insertions, 526 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/extra/ActionListener.java b/src/main/java/com/google/devtools/build/lib/rules/extra/ActionListener.java index 1505e44054..105c4b7a52 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/extra/ActionListener.java +++ b/src/main/java/com/google/devtools/build/lib/rules/extra/ActionListener.java @@ -23,6 +23,8 @@ import com.google.devtools.build.lib.analysis.RuleContext; import com.google.devtools.build.lib.analysis.Runfiles; import com.google.devtools.build.lib.analysis.RunfilesProvider; import com.google.devtools.build.lib.analysis.TransitiveInfoCollection; +import com.google.devtools.build.lib.analysis.extra.ExtraActionMapProvider; +import com.google.devtools.build.lib.analysis.extra.ExtraActionSpec; import com.google.devtools.build.lib.collect.ImmutableSortedKeyListMultimap; import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException; import com.google.devtools.build.lib.syntax.Type; diff --git a/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraAction.java b/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraAction.java deleted file mode 100644 index 41ba32c5fd..0000000000 --- a/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraAction.java +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright 2014 The Bazel Authors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package com.google.devtools.build.lib.rules.extra; - -import com.google.common.base.Function; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Sets; -import com.google.devtools.build.lib.actions.AbstractAction; -import com.google.devtools.build.lib.actions.Action; -import com.google.devtools.build.lib.actions.ActionEnvironment; -import com.google.devtools.build.lib.actions.ActionExecutionContext; -import com.google.devtools.build.lib.actions.ActionExecutionException; -import com.google.devtools.build.lib.actions.Artifact; -import com.google.devtools.build.lib.actions.CompositeRunfilesSupplier; -import com.google.devtools.build.lib.actions.RunfilesSupplier; -import com.google.devtools.build.lib.actions.SpawnActionContext; -import com.google.devtools.build.lib.analysis.actions.CommandLine; -import com.google.devtools.build.lib.analysis.actions.SpawnAction; -import com.google.devtools.build.lib.collect.nestedset.NestedSet; -import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; -import com.google.devtools.build.lib.collect.nestedset.Order; -import com.google.devtools.build.lib.util.Preconditions; -import com.google.devtools.build.lib.vfs.FileSystemUtils; -import java.io.IOException; -import java.util.Collection; -import java.util.Map; -import javax.annotation.Nullable; - -/** - * Action used by extra_action rules to create an action that shadows an existing action. Runs a - * command-line using {@link SpawnActionContext} for executions. - */ -public final class ExtraAction extends SpawnAction { - private final Action shadowedAction; - private final boolean createDummyOutput; - private final ImmutableSet<Artifact> extraActionInputs; - - /** - * A long way to say (ExtraAction xa) -> xa.getShadowedAction(). - */ - public static final Function<ExtraAction, Action> GET_SHADOWED_ACTION = - new Function<ExtraAction, Action>() { - @Nullable - @Override - public Action apply(@Nullable ExtraAction extraAction) { - return extraAction != null ? extraAction.getShadowedAction() : null; - } - }; - - ExtraAction( - ImmutableSet<Artifact> extraActionInputs, - RunfilesSupplier runfilesSupplier, - Collection<Artifact> outputs, - Action shadowedAction, - boolean createDummyOutput, - CommandLine argv, - ActionEnvironment env, - Map<String, String> executionInfo, - CharSequence progressMessage, - String mnemonic) { - super( - shadowedAction.getOwner(), - ImmutableList.<Artifact>of(), - createInputs(shadowedAction.getInputs(), ImmutableList.<Artifact>of(), extraActionInputs), - outputs, - AbstractAction.DEFAULT_RESOURCE_SET, - argv, - false, - env, - ImmutableMap.copyOf(executionInfo), - progressMessage, - new CompositeRunfilesSupplier(shadowedAction.getRunfilesSupplier(), runfilesSupplier), - mnemonic, - false, - null); - this.shadowedAction = shadowedAction; - this.createDummyOutput = createDummyOutput; - - this.extraActionInputs = extraActionInputs; - if (createDummyOutput) { - // Expecting just a single dummy file in the outputs. - Preconditions.checkArgument(outputs.size() == 1, outputs); - } - } - - @Override - public boolean discoversInputs() { - return shadowedAction.discoversInputs(); - } - - @Nullable - @Override - public Iterable<Artifact> discoverInputs(ActionExecutionContext actionExecutionContext) - throws ActionExecutionException, InterruptedException { - Preconditions.checkState(discoversInputs(), this); - // We depend on the outputs of actions doing input discovery and they should know their inputs - // after having been executed - Preconditions.checkState(shadowedAction.inputsDiscovered()); - - // We need to update our inputs to take account of any additional - // inputs the shadowed action may need to do its work. - Iterable<Artifact> oldInputs = getInputs(); - updateInputs( - createInputs( - shadowedAction.getInputs(), - shadowedAction.getInputFilesForExtraAction(actionExecutionContext), - extraActionInputs)); - return Sets.<Artifact>difference( - ImmutableSet.<Artifact>copyOf(getInputs()), ImmutableSet.<Artifact>copyOf(oldInputs)); - } - - private static NestedSet<Artifact> createInputs( - Iterable<Artifact> shadowedActionInputs, - Iterable<Artifact> inputFilesForExtraAction, - ImmutableSet<Artifact> extraActionInputs) { - NestedSetBuilder<Artifact> result = new NestedSetBuilder<>(Order.STABLE_ORDER); - for (Iterable<Artifact> inputSet : ImmutableList.of( - shadowedActionInputs, inputFilesForExtraAction)) { - if (inputSet instanceof NestedSet) { - result.addTransitive((NestedSet<Artifact>) inputSet); - } else { - result.addAll(inputSet); - } - } - return result.addAll(extraActionInputs).build(); - } - - @Override - public Iterable<Artifact> getAllowedDerivedInputs() { - return shadowedAction.getAllowedDerivedInputs(); - } - - /** - * @InheritDoc - * - * This method calls in to {@link AbstractAction#getInputFilesForExtraAction} and - * {@link Action#getExtraActionInfo} of the action being shadowed from the thread executing this - * ExtraAction. It assumes these methods are safe to call from a different thread than the thread - * responsible for the execution of the action being shadowed. - */ - @Override - public void execute(ActionExecutionContext actionExecutionContext) - throws ActionExecutionException, InterruptedException { - // PHASE 2: execution of extra_action. - - super.execute(actionExecutionContext); - - // PHASE 3: create dummy output. - // If the user didn't specify output, we need to create dummy output - // to make blaze schedule this action. - if (createDummyOutput) { - for (Artifact output : getOutputs()) { - try { - FileSystemUtils.touchFile(output.getPath()); - } catch (IOException e) { - throw new ActionExecutionException(e.getMessage(), e, this, false); - } - } - } - } - - /** - * Returns the action this extra action is 'shadowing'. - */ - public Action getShadowedAction() { - return shadowedAction; - } -} diff --git a/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraActionFactory.java b/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraActionFactory.java index 1d0def104f..c3fe6b940b 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraActionFactory.java +++ b/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraActionFactory.java @@ -29,6 +29,7 @@ import com.google.devtools.build.lib.analysis.RuleContext; import com.google.devtools.build.lib.analysis.Runfiles; import com.google.devtools.build.lib.analysis.RunfilesProvider; import com.google.devtools.build.lib.analysis.TransitiveInfoCollection; +import com.google.devtools.build.lib.analysis.extra.ExtraActionSpec; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.packages.TargetUtils; import com.google.devtools.build.lib.syntax.Type; diff --git a/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraActionInfoFileWriteAction.java b/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraActionInfoFileWriteAction.java deleted file mode 100644 index 36fee0385f..0000000000 --- a/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraActionInfoFileWriteAction.java +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2015 The Bazel Authors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -package com.google.devtools.build.lib.rules.extra; - -import com.google.common.collect.ImmutableList; -import com.google.devtools.build.lib.actions.Action; -import com.google.devtools.build.lib.actions.ActionExecutionContext; -import com.google.devtools.build.lib.actions.ActionOwner; -import com.google.devtools.build.lib.actions.Artifact; -import com.google.devtools.build.lib.actions.ExecException; -import com.google.devtools.build.lib.analysis.actions.AbstractFileWriteAction; -import com.google.devtools.build.lib.analysis.actions.ProtoDeterministicWriter; -import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; -import com.google.devtools.build.lib.util.Fingerprint; -import com.google.devtools.build.lib.util.Preconditions; -import java.io.IOException; - -/** - * Requests extra action info from shadowed action and writes it, in protocol buffer format, to an - * .xa file for use by an extra action. This can only be done at execution time because actions may - * store information only known at execution time into the protocol buffer. - */ -@Immutable // if shadowedAction is immutable -public final class ExtraActionInfoFileWriteAction extends AbstractFileWriteAction { - private static final String UUID = "1759f81d-e72e-477d-b182-c4532bdbaeeb"; - - private final Action shadowedAction; - - ExtraActionInfoFileWriteAction(ActionOwner owner, Artifact extraActionInfoFile, - Action shadowedAction) { - super(owner, ImmutableList.<Artifact>of(), extraActionInfoFile, false); - - this.shadowedAction = Preconditions.checkNotNull(shadowedAction, extraActionInfoFile); - } - - @Override - public DeterministicWriter newDeterministicWriter(ActionExecutionContext ctx) - throws IOException, InterruptedException, ExecException { - return new ProtoDeterministicWriter(shadowedAction.getExtraActionInfo().build()); - } - - @Override - protected String computeKey() { - Fingerprint f = new Fingerprint(); - f.addString(UUID); - f.addString(shadowedAction.getKey()); - f.addBytes(shadowedAction.getExtraActionInfo().build().toByteArray()); - return f.hexDigestAndReset(); - } -} diff --git a/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraActionMapProvider.java b/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraActionMapProvider.java deleted file mode 100644 index 50e6c800d1..0000000000 --- a/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraActionMapProvider.java +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2014 The Bazel Authors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -package com.google.devtools.build.lib.rules.extra; - -import com.google.common.collect.ImmutableMultimap; -import com.google.common.collect.Multimap; -import com.google.devtools.build.lib.analysis.TransitiveInfoProvider; -import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; - -/** - * Provides an action type -> set of extra actions to run map. - */ -@Immutable -public final class ExtraActionMapProvider implements TransitiveInfoProvider { - private final ImmutableMultimap<String, ExtraActionSpec> extraActionMap; - - public ExtraActionMapProvider(Multimap<String, ExtraActionSpec> extraActionMap) { - this.extraActionMap = ImmutableMultimap.copyOf(extraActionMap); - } - - /** - * Returns the extra action map. - */ - public ImmutableMultimap<String, ExtraActionSpec> getExtraActionMap() { - return extraActionMap; - } -} diff --git a/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraActionSpec.java b/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraActionSpec.java deleted file mode 100644 index 3ccda08af2..0000000000 --- a/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraActionSpec.java +++ /dev/null @@ -1,245 +0,0 @@ -// Copyright 2014 The Bazel Authors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -package com.google.devtools.build.lib.rules.extra; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.devtools.build.lib.actions.Action; -import com.google.devtools.build.lib.actions.ActionOwner; -import com.google.devtools.build.lib.actions.Artifact; -import com.google.devtools.build.lib.actions.RunfilesSupplier; -import com.google.devtools.build.lib.analysis.CommandHelper; -import com.google.devtools.build.lib.analysis.RuleContext; -import com.google.devtools.build.lib.analysis.TransitiveInfoCollection; -import com.google.devtools.build.lib.analysis.TransitiveInfoProvider; -import com.google.devtools.build.lib.analysis.actions.CommandLine; -import com.google.devtools.build.lib.cmdline.Label; -import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; -import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; -import com.google.devtools.build.lib.packages.AspectDescriptor; -import com.google.devtools.build.lib.util.Fingerprint; -import com.google.devtools.build.lib.vfs.PathFragment; -import java.util.ArrayList; -import java.util.Collection; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; - -/** - * The specification for a particular extra action type. - */ -@Immutable -public final class ExtraActionSpec implements TransitiveInfoProvider { - private final ImmutableList<Artifact> resolvedTools; - private final RunfilesSupplier runfilesSupplier; - private final ImmutableList<Artifact> resolvedData; - private final ImmutableList<String> outputTemplates; - private final ImmutableMap<String, String> executionInfo; - private final String command; - private final boolean requiresActionOutput; - private final Label label; - - ExtraActionSpec( - Iterable<Artifact> resolvedTools, - RunfilesSupplier runfilesSupplier, - Iterable<Artifact> resolvedData, - Iterable<String> outputTemplates, - String command, - Label label, - Map<String, String> executionInfo, - boolean requiresActionOutput) { - this.resolvedTools = ImmutableList.copyOf(resolvedTools); - this.runfilesSupplier = runfilesSupplier; - this.resolvedData = ImmutableList.copyOf(resolvedData); - this.outputTemplates = ImmutableList.copyOf(outputTemplates); - this.command = command; - this.label = label; - this.executionInfo = ImmutableMap.copyOf(executionInfo); - this.requiresActionOutput = requiresActionOutput; - } - - public Label getLabel() { - return label; - } - - /** - * Adds an extra_action to the action graph based on the action to shadow. - */ - public Collection<Artifact> addExtraAction(RuleContext owningRule, Action actionToShadow) { - Collection<Artifact> extraActionOutputs = new LinkedHashSet<>(); - Collection<Artifact> protoOutputs = new ArrayList<>(); - NestedSetBuilder<Artifact> extraActionInputs = NestedSetBuilder.stableOrder(); - - Label ownerLabel = owningRule.getLabel(); - if (requiresActionOutput || actionToShadow.discoversInputs()) { - extraActionInputs.addAll(actionToShadow.getOutputs()); - } - - extraActionInputs.addAll(resolvedTools); - extraActionInputs.addAll(resolvedData); - - boolean createDummyOutput = false; - - for (String outputTemplate : outputTemplates) { - // We create output for the extra_action based on the 'out_template' attribute. - // See {link #getExtraActionOutputArtifact} for supported variables. - extraActionOutputs.add(getExtraActionOutputArtifact( - owningRule, actionToShadow, outputTemplate)); - } - // extra_action has no output, we need to create some dummy output to keep the build up-to-date. - if (extraActionOutputs.isEmpty()) { - createDummyOutput = true; - extraActionOutputs.add(getExtraActionOutputArtifact( - owningRule, actionToShadow, "$(ACTION_ID).dummy")); - } - - // We generate a file containing a protocol buffer describing the action that is being shadowed. - // It is up to each action being shadowed to decide what contents to store here. - Artifact extraActionInfoFile = getExtraActionOutputArtifact( - owningRule, actionToShadow, "$(ACTION_ID).xa"); - owningRule.registerAction(new ExtraActionInfoFileWriteAction( - actionToShadow.getOwner(), extraActionInfoFile, actionToShadow)); - extraActionInputs.add(extraActionInfoFile); - protoOutputs.add(extraActionInfoFile); - - // Expand extra_action specific variables from the provided command-line. - // See {@link #createExpandedCommand} for list of supported variables. - String command = createExpandedCommand(owningRule, actionToShadow, extraActionInfoFile); - - CommandHelper commandHelper = - new CommandHelper( - owningRule, - ImmutableList.<TransitiveInfoCollection>of(), - ImmutableMap.<Label, Iterable<Artifact>>of()); - - // Multiple actions in the same configured target need to have different names for the artifact - // that might be created here, so we append something that should be unique for each action. - String actionUniquifier = actionToShadow.getPrimaryOutput().getExecPath().getBaseName() + "." - + actionToShadow.getKey(); - List<String> argv = commandHelper.buildCommandLine(command, extraActionInputs, - "." + actionUniquifier + ".extra_action_script.sh", executionInfo); - - String commandMessage = String.format("Executing extra_action %s on %s", label, ownerLabel); - owningRule.registerAction( - new ExtraAction( - ImmutableSet.copyOf(extraActionInputs.build()), - runfilesSupplier, - extraActionOutputs, - actionToShadow, - createDummyOutput, - CommandLine.of(argv), - owningRule.getConfiguration().getActionEnvironment(), - executionInfo, - commandMessage, - label.getName())); - - return ImmutableSet.<Artifact>builder().addAll(extraActionOutputs).addAll(protoOutputs).build(); - } - - /** - * Expand extra_action specific variables: - * $(EXTRA_ACTION_FILE): expands to a path of the file containing a protocol buffer - * describing the action being shadowed. - * $(output <out_template>): expands the output template to the execPath of the file. - * e.g. $(output $(ACTION_ID).out) -> - * <build_path>/extra_actions/bar/baz/devtools/build/test_A41234.out - */ - private String createExpandedCommand(RuleContext owningRule, - Action action, Artifact extraActionInfoFile) { - String realCommand = command.replace( - "$(EXTRA_ACTION_FILE)", extraActionInfoFile.getExecPathString()); - - for (String outputTemplate : outputTemplates) { - String outFile = getExtraActionOutputArtifact(owningRule, action, outputTemplate) - .getExecPathString(); - realCommand = realCommand.replace("$(output " + outputTemplate + ")", outFile); - } - return realCommand; - } - - /** - * Creates an output artifact for the extra_action based on the output_template. - * The path will be in the following form: - * <output dir>/<target-configuration-specific-path>/extra_actions/<extra_action_label>/ + - * <configured_target_label>/<expanded_template> - * - * The template can use the following variables: - * $(ACTION_ID): a unique id for the extra_action. - * - * Sample: - * extra_action: foo/bar:extra - * template: $(ACTION_ID).analysis - * target: foo/bar:main - * expands to: output/configuration/extra_actions/\ - * foo/bar/extra/foo/bar/4683026f7ac1dd1a873ccc8c3d764132.analysis - */ - private Artifact getExtraActionOutputArtifact( - RuleContext ruleContext, Action action, String template) { - String actionId = getActionId(ruleContext.getActionOwner(), action); - - template = template.replace("$(ACTION_ID)", actionId); - template = template.replace("$(OWNER_LABEL_DIGEST)", getOwnerDigest(ruleContext)); - - return getRootRelativePath(template, ruleContext); - } - - private Artifact getRootRelativePath(String template, RuleContext ruleContext) { - PathFragment extraActionPackageFragment = label.getPackageIdentifier().getSourceRoot(); - PathFragment extraActionPrefix = extraActionPackageFragment.getRelative(label.getName()); - PathFragment rootRelativePath = PathFragment.create("extra_actions") - .getRelative(extraActionPrefix) - .getRelative(ruleContext.getPackageDirectory()) - .getRelative(template); - // We need to use getDerivedArtifact here because extra actions are at - // <EXTRA ACTION LABEL> / <RULE LABEL> instead of <RULE LABEL> / <EXTRA ACTION LABEL>. Bummer. - return ruleContext.getAnalysisEnvironment().getDerivedArtifact(rootRelativePath, - ruleContext.getConfiguration().getOutputDirectory(ruleContext.getRule().getRepository())); - } - - /** - * Calculates a digest representing the rule context. We use the digest instead of the - * original value as the original value might lead to a filename that is too long. - * By using a digest, tools can deterministically find all extra_action outputs for a given - * target, without having to open every file in the package. - */ - private static String getOwnerDigest(RuleContext ruleContext) { - Fingerprint f = new Fingerprint(); - f.addString(ruleContext.getLabel().toString()); - return f.hexDigestAndReset(); - } - - /** - * Creates a unique id for the action shadowed by this extra_action. - * - * We need to have a unique id for the extra_action to use. We build this - * from the owner's label and the shadowed action id (which is only - * guaranteed to be unique per target). Together with the subfolder - * matching the original target's package name, we believe this is enough - * of a uniqueness guarantee. - */ - @VisibleForTesting - public static String getActionId(ActionOwner owner, Action action) { - Fingerprint f = new Fingerprint(); - f.addString(owner.getLabel().toString()); - ImmutableList<AspectDescriptor> aspectDescriptors = owner.getAspectDescriptors(); - f.addInt(aspectDescriptors.size()); - for (AspectDescriptor aspectDescriptor : aspectDescriptors) { - f.addString(aspectDescriptor.getDescription()); - } - f.addString(action.getKey()); - return f.hexDigestAndReset(); - } -} |