PageRenderTime 49ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/test/com/facebook/buck/rules/AbstractNodeBuilder.java

https://gitlab.com/smartether/buck
Java | 251 lines | 192 code | 29 blank | 30 comment | 6 complexity | 4cd939500275cbc1311659515c4ef67e MD5 | raw file
  1. /*
  2. * Copyright 2014-present Facebook, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may
  5. * not use this file except in compliance with the License. You may obtain
  6. * a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations
  14. * under the License.
  15. */
  16. package com.facebook.buck.rules;
  17. import static java.nio.charset.StandardCharsets.UTF_8;
  18. import com.facebook.buck.io.ProjectFilesystem;
  19. import com.facebook.buck.model.BuildTarget;
  20. import com.facebook.buck.parser.NoSuchBuildTargetException;
  21. import com.facebook.buck.rules.coercer.DefaultTypeCoercerFactory;
  22. import com.facebook.buck.rules.coercer.TypeCoercerFactory;
  23. import com.facebook.buck.testutil.FakeProjectFilesystem;
  24. import com.facebook.buck.util.ObjectMappers;
  25. import com.facebook.buck.versions.Version;
  26. import com.google.common.collect.ImmutableMap;
  27. import com.google.common.collect.ImmutableSet;
  28. import com.google.common.collect.ImmutableSortedSet;
  29. import com.google.common.hash.HashCode;
  30. import com.google.common.hash.Hashing;
  31. import java.lang.reflect.Field;
  32. import java.util.Optional;
  33. import javax.annotation.Nullable;
  34. /**
  35. * Support class for writing builders for nodes of a {@link TargetGraph}
  36. * and {@link ActionGraph} ({@link TargetNode} and {@link BuildRule} respectively) mirroring the
  37. * behavior seen when running the actual parser as closely as possible.
  38. */
  39. public abstract class AbstractNodeBuilder<
  40. TArg,
  41. TDescription extends Description<TArg>,
  42. TBuildRule extends BuildRule> {
  43. private static final TypeCoercerFactory TYPE_COERCER_FACTORY =
  44. new DefaultTypeCoercerFactory(ObjectMappers.newDefaultInstance());
  45. private static final CoercedTypeCache COERCED_TYPE_CACHE =
  46. new CoercedTypeCache(TYPE_COERCER_FACTORY);
  47. private static final VisibilityPatternParser VISIBILITY_PATTERN_PARSER =
  48. new VisibilityPatternParser();
  49. protected final TDescription description;
  50. protected final ProjectFilesystem filesystem;
  51. protected final BuildTarget target;
  52. protected final TArg arg;
  53. private final CellPathResolver cellRoots;
  54. @Nullable
  55. private final HashCode rawHashCode;
  56. private Optional<ImmutableMap<BuildTarget, Version>> selectedVersions = Optional.empty();
  57. protected AbstractNodeBuilder(
  58. TDescription description,
  59. BuildTarget target) {
  60. this(description, target, new FakeProjectFilesystem(), null);
  61. }
  62. protected AbstractNodeBuilder(
  63. TDescription description,
  64. BuildTarget target,
  65. ProjectFilesystem projectFilesystem) {
  66. this(description, target, projectFilesystem, null);
  67. }
  68. protected AbstractNodeBuilder(
  69. TDescription description,
  70. BuildTarget target,
  71. ProjectFilesystem projectFilesystem,
  72. HashCode hashCode) {
  73. this.description = description;
  74. this.filesystem = projectFilesystem;
  75. this.target = target;
  76. this.rawHashCode = hashCode;
  77. this.cellRoots = new FakeCellPathResolver(projectFilesystem);
  78. this.arg = description.createUnpopulatedConstructorArg();
  79. populateWithDefaultValues(this.arg);
  80. }
  81. public final TBuildRule build(BuildRuleResolver resolver) throws NoSuchBuildTargetException {
  82. return build(resolver, filesystem, TargetGraph.EMPTY);
  83. }
  84. public final TBuildRule build(BuildRuleResolver resolver, TargetGraph targetGraph)
  85. throws NoSuchBuildTargetException {
  86. return build(resolver, filesystem, targetGraph);
  87. }
  88. public final TBuildRule build(BuildRuleResolver resolver, ProjectFilesystem filesystem)
  89. throws NoSuchBuildTargetException {
  90. return build(resolver, filesystem, TargetGraph.EMPTY);
  91. }
  92. public final TBuildRule build(
  93. BuildRuleResolver resolver,
  94. ProjectFilesystem filesystem,
  95. TargetGraph targetGraph) throws NoSuchBuildTargetException {
  96. // The BuildRule determines its deps by extracting them from the rule parameters.
  97. BuildRuleParams params = createBuildRuleParams(resolver, filesystem);
  98. @SuppressWarnings("unchecked")
  99. TBuildRule rule =
  100. (TBuildRule) description.createBuildRule(targetGraph, params, resolver, cellRoots, arg);
  101. resolver.addToIndex(rule);
  102. return rule;
  103. }
  104. public TargetNode<TArg, TDescription> build() {
  105. try {
  106. HashCode hash = rawHashCode == null ?
  107. Hashing.sha1().hashString(target.getFullyQualifiedName(), UTF_8) :
  108. rawHashCode;
  109. TargetNodeFactory factory = new TargetNodeFactory(TYPE_COERCER_FACTORY);
  110. TargetNode<TArg, TDescription> node =
  111. factory.create(
  112. // This hash will do in a pinch.
  113. hash,
  114. description,
  115. arg,
  116. filesystem,
  117. target,
  118. getDepsFromArg(),
  119. ImmutableSet.of(
  120. VISIBILITY_PATTERN_PARSER.parse(
  121. null,
  122. VisibilityPatternParser.VISIBILITY_PUBLIC)),
  123. ImmutableSet.of(),
  124. cellRoots);
  125. if (selectedVersions.isPresent()) {
  126. node =
  127. node.withTargetConstructorArgDepsAndSelectedVerisons(
  128. node.getBuildTarget(),
  129. node.getConstructorArg(),
  130. node.getDeclaredDeps(),
  131. node.getExtraDeps(),
  132. node.getTargetGraphOnlyDeps(),
  133. selectedVersions);
  134. }
  135. return node;
  136. } catch (NoSuchBuildTargetException e) {
  137. throw new RuntimeException(e);
  138. }
  139. }
  140. public BuildRuleParams createBuildRuleParams(
  141. BuildRuleResolver resolver,
  142. ProjectFilesystem filesystem) {
  143. TargetNode<?, ?> node = build();
  144. return new FakeBuildRuleParamsBuilder(target)
  145. .setProjectFilesystem(filesystem)
  146. .setDeclaredDeps(resolver.getAllRules(node.getDeclaredDeps()))
  147. .setExtraDeps(resolver.getAllRules(node.getExtraDeps()))
  148. .build();
  149. }
  150. @SuppressWarnings("unchecked")
  151. private ImmutableSortedSet<BuildTarget> getDepsFromArg() {
  152. // Not all rules have deps, but all rules call them deps. When they do, they're always optional.
  153. // Grab them in the unsafest way I know.
  154. try {
  155. Field depsField = arg.getClass().getField("deps");
  156. Object deps = depsField.get(arg);
  157. if (deps == null) {
  158. return ImmutableSortedSet.of();
  159. }
  160. // Here's a whole series of assumptions in one lump of a Bad Idea.
  161. return (ImmutableSortedSet<BuildTarget>) deps;
  162. } catch (ReflectiveOperationException ignored) {
  163. // Field doesn't exist: no deps.
  164. return ImmutableSortedSet.of();
  165. }
  166. }
  167. protected <C extends Comparable<?>> ImmutableSortedSet<C> amend(
  168. ImmutableSortedSet<C> existing,
  169. C instance) {
  170. ImmutableSortedSet.Builder<C> toReturn = ImmutableSortedSet.naturalOrder();
  171. if (existing != null) {
  172. toReturn.addAll(existing);
  173. }
  174. toReturn.add(instance);
  175. return toReturn.build();
  176. }
  177. // Thanks to type erasure, this needs a unique name.
  178. protected <C extends Comparable<?>> ImmutableSet<C> amendSet(
  179. ImmutableSet<C> existing,
  180. C instance) {
  181. ImmutableSet.Builder<C> toReturn = ImmutableSet.builder();
  182. toReturn.addAll(existing);
  183. toReturn.add(instance);
  184. return toReturn.build();
  185. }
  186. /**
  187. * Populate optional fields of this constructor arg with their default values.
  188. */
  189. private void populateWithDefaultValues(TArg arg) {
  190. try {
  191. new ConstructorArgMarshaller(COERCED_TYPE_CACHE)
  192. .populateDefaults(
  193. cellRoots,
  194. filesystem,
  195. target,
  196. arg);
  197. } catch (ParamInfoException error) {
  198. throw new RuntimeException(error);
  199. }
  200. }
  201. @SuppressWarnings("unchecked")
  202. public ImmutableSortedSet<BuildTarget> findImplicitDeps() {
  203. ImplicitDepsInferringDescription<TArg> desc =
  204. (ImplicitDepsInferringDescription<TArg>) description;
  205. ImmutableSortedSet.Builder<BuildTarget> builder = ImmutableSortedSet.naturalOrder();
  206. desc.findDepsForTargetFromConstructorArgs(
  207. target,
  208. cellRoots,
  209. arg,
  210. builder,
  211. ImmutableSortedSet.naturalOrder());
  212. return builder.build();
  213. }
  214. public BuildTarget getTarget() {
  215. return target;
  216. }
  217. public AbstractNodeBuilder<TArg, TDescription, TBuildRule> setSelectedVersions(
  218. ImmutableMap<BuildTarget, Version> selectedVersions) {
  219. this.selectedVersions = Optional.of(selectedVersions);
  220. return this;
  221. }
  222. }