buildSrc/src/main/java/com/uber/okbuck/core/annotation/AnnotationProcessorCache.java [27:256]:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
public class AnnotationProcessorCache {
  public static final String AUTO_VALUE_GROUP = "com.google.auto.value";
  public static final String AUTO_VALUE_NAME = "auto-value";

  private final Project project;
  private final BuckFileManager buckFileManager;
  private final String processorBuckFile;
  private final Map<Set<Dependency>, Scope> dependencyToScopeMap;

  @Nullable private Map<Set<Dependency>, Scope> autoValueDependencyToScopeMap;

  public AnnotationProcessorCache(
      Project project, BuckFileManager buckFileManager, String processorBuckFile) {
    this.project = project;
    this.buckFileManager = buckFileManager;
    this.processorBuckFile = processorBuckFile;
    this.dependencyToScopeMap = new ConcurrentHashMap<>();
  }

  @Synchronized
  private Map<Set<Dependency>, Scope> getAutoValueDependencyToScopeMap() {
    if (autoValueDependencyToScopeMap == null) {
      Project rootProject = project.getRootProject();
      ExternalDependenciesExtension extension = ProjectUtil.getExternalDependencyExtension(project);

      autoValueDependencyToScopeMap =
          createAutoValueProcessorScopes(rootProject, extension.getAutoValueConfigurations());
    }
    return autoValueDependencyToScopeMap;
  }

  /**
   * Get all the scopes for the specified configuration. Returns one configuration per dependency.
   * Will group auto value and its extensions together into one scope as well.
   *
   * @param project project on which the configuration is defined.
   * @param configurationString Configuration string which is used to query the deps.
   * @return A list of scopes generated by the configuration.
   */
  public List<Scope> getAnnotationProcessorScopes(Project project, String configurationString) {
    Optional<Configuration> configuration = getConfiguration(project, configurationString);
    return configuration.isPresent()
        ? getAnnotationProcessorScopes(project, configuration.get())
        : ImmutableList.of();
  }

  /**
   * Get all the scopes for the specified configuration. Returns one configuration per dependency.
   * Will group auto value and its extensions together into one scope as well.
   *
   * @param project project on which the configuration is defined.
   * @param configuration Configuration which is used to query the deps.
   * @return A list of scopes generated by the configuration.
   */
  public List<Scope> getAnnotationProcessorScopes(Project project, Configuration configuration) {
    ImmutableList.Builder<Scope> scopesBuilder = ImmutableList.builder();

    Map<Dependency, Scope> singleDependencyToScope =
        createProcessorScopes(project, configuration.getAllDependencies());

    Set<Dependency> autoValueDependencies = getAutoValueDependencies(singleDependencyToScope);

    if (autoValueDependencies.size() > 0) {
      Map<Set<Dependency>, Scope> autoValueScopeMap = getAutoValueDependencyToScopeMap();
      if (autoValueScopeMap.size() == 0) {
        throw new IllegalStateException(
            "autoValueConfigurations should be present if adding autoValue dependencies. missing: "
                + autoValueDependencies);
      }
      if (!autoValueScopeMap.containsKey(autoValueDependencies)) {
        throw new IllegalStateException(
            "autoValueConfigurations declared mismatch the autoValue dependencies. missing: "
                + autoValueDependencies + " found: " + autoValueScopeMap.keySet());
      }
      scopesBuilder.add(autoValueScopeMap.get(autoValueDependencies));

      singleDependencyToScope.forEach(
          (dependency, scope) -> {
            if (!autoValueDependencies.contains(dependency)) {
              scopesBuilder.add(scope);
            }
          });
    } else {
      scopesBuilder.addAll(singleDependencyToScope.values());
    }

    return scopesBuilder.build();
  }

  private static ImmutableSet<Dependency> getAutoValueDependencies(
      Map<Dependency, Scope> dependencyToScope) {
    return dependencyToScope
        .entrySet()
        .stream()
        .filter(entry -> isAutoValueScope(entry.getValue()))
        .map(Map.Entry::getKey)
        .collect(ImmutableSet.toImmutableSet());
  }

  private static boolean isAutoValueScope(Scope scope) {
    return scope
        .getExternalDeps()
        .stream()
        .anyMatch(
            dependency -> {
              if (dependency.getGroup().equals(AUTO_VALUE_GROUP)
                  || dependency.getName().startsWith(AUTO_VALUE_NAME)) {
                return true;
              }

              return scope.hasAutoValueExtensions();
            });
  }

  /**
   * Checks if the configuration has any empty annotation processors.
   *
   * @param project project on which the configuration is defined.
   * @param configurationString ConfigurationString which is used to query the deps.
   * @return A boolean whether the configuration has any empty annotation processors.
   */
  @SuppressWarnings("BooleanMethodIsAlwaysInverted")
  public boolean hasEmptyAnnotationProcessors(Project project, String configurationString) {
    Optional<Configuration> configuration = getConfiguration(project, configurationString);
    return configuration.map(config -> hasEmptyAnnotationProcessors(project, config)).orElse(false);
  }

  /**
   * Checks if the configuration has any empty annotation processors.
   *
   * @param project project on which the configuration is defined.
   * @param configuration Configuration which is used to query the deps.
   * @return A boolean whether the configuration has any empty annotation processors.
   */
  public boolean hasEmptyAnnotationProcessors(Project project, Configuration configuration) {
    Map<Dependency, Scope> depToScope =
        createProcessorScopes(project, configuration.getAllDependencies());

    return depToScope
        .values()
        .stream()
        .anyMatch(scope -> scope.getAnnotationProcessors().isEmpty());
  }

  /** Write the buck file for the java_annotation_processor rules. */
  public Map<Path, List<Scope>> getBasePathToExternalDependencyScopeMap() {
    Path rootPath = project.getRootDir().toPath();

    return dependencyToScopeMap
        .values()
        .stream()
        .filter(it -> it.getAnnotationProcessorPlugin().pluginDependency().isPresent())
        .collect(
            Collectors.groupingBy(
                scope ->
                    rootPath.resolve(
                        scope
                            .getAnnotationProcessorPlugin()
                            .pluginDependency()
                            .get()
                            .getTargetPath())));
  }

  public void finalizeProcessors() {
    List<Scope> targetScopes =
        dependencyToScopeMap
            .values()
            .stream()
            .filter(it -> !it.getAnnotationProcessorPlugin().pluginDependency().isPresent())
            .collect(Collectors.toList());

    buckFileManager.writeToBuckFile(
        JavaAnnotationProcessorRuleComposer.compose(targetScopes),
        project.getRootProject().file(processorBuckFile));
  }

  private ImmutableMap<Dependency, Scope> createProcessorScopes(
      Project project, Set<Dependency> dependencies) {

    ImmutableMap.Builder<Dependency, Scope> currentBuilder = new ImmutableMap.Builder<>();

    // Creates a scope using a detached configuration and the given dependency set.
    Function<Set<Dependency>, Scope> computeScope =
        depSet -> {
          Dependency[] depArray = depSet.toArray(new Dependency[0]);
          Configuration detached = project.getConfigurations().detachedConfiguration(depArray);
          return Scope.builder(project).configuration(detached).build();
        };

    // Creates one scope per dependency if not already
    // found and adds it to the current builder.
    dependencies.forEach(
        dependency -> {
          ImmutableSet<Dependency> dependencySet = ImmutableSet.of(dependency);
          Scope scope = dependencyToScopeMap.computeIfAbsent(dependencySet, computeScope);
          currentBuilder.put(dependency, scope);
        });

    return currentBuilder.build();
  }

  private ImmutableMap<Set<Dependency>, Scope> createAutoValueProcessorScopes(
      Project project, Set<String> configurations) {
    ImmutableMap.Builder<Set<Dependency>, Scope> currentBuilder = new ImmutableMap.Builder<>();

    for (String configurationString : configurations) {
      Optional<Configuration> optionalConfiguration =
          getConfiguration(project, configurationString);

      if (optionalConfiguration.isPresent()
          && optionalConfiguration.get().getAllDependencies().size() > 0) {
        Configuration configuration = optionalConfiguration.get();

        ImmutableSet<Dependency> dependencySet =
            ImmutableSet.copyOf(configuration.getAllDependencies());
        Scope scope =
            dependencyToScopeMap.computeIfAbsent(
                dependencySet,
                depSet -> Scope.builder(project).configuration(configuration).build());

        currentBuilder.put(dependencySet, scope);
      }
    }
    return currentBuilder.build();
  }

  private static Optional<Configuration> getConfiguration(
      Project project, String configurationString) {
    Configuration configuration = DependencyUtils.useful(configurationString, project);
    return Optional.ofNullable(configuration);
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -



plugin/src/main/java/com/uber/okbuck/core/annotation/AnnotationProcessorCache.java [27:256]:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
public class AnnotationProcessorCache {
  public static final String AUTO_VALUE_GROUP = "com.google.auto.value";
  public static final String AUTO_VALUE_NAME = "auto-value";

  private final Project project;
  private final BuckFileManager buckFileManager;
  private final String processorBuckFile;
  private final Map<Set<Dependency>, Scope> dependencyToScopeMap;

  @Nullable private Map<Set<Dependency>, Scope> autoValueDependencyToScopeMap;

  public AnnotationProcessorCache(
      Project project, BuckFileManager buckFileManager, String processorBuckFile) {
    this.project = project;
    this.buckFileManager = buckFileManager;
    this.processorBuckFile = processorBuckFile;
    this.dependencyToScopeMap = new ConcurrentHashMap<>();
  }

  @Synchronized
  private Map<Set<Dependency>, Scope> getAutoValueDependencyToScopeMap() {
    if (autoValueDependencyToScopeMap == null) {
      Project rootProject = project.getRootProject();
      ExternalDependenciesExtension extension = ProjectUtil.getExternalDependencyExtension(project);

      autoValueDependencyToScopeMap =
          createAutoValueProcessorScopes(rootProject, extension.getAutoValueConfigurations());
    }
    return autoValueDependencyToScopeMap;
  }

  /**
   * Get all the scopes for the specified configuration. Returns one configuration per dependency.
   * Will group auto value and its extensions together into one scope as well.
   *
   * @param project project on which the configuration is defined.
   * @param configurationString Configuration string which is used to query the deps.
   * @return A list of scopes generated by the configuration.
   */
  public List<Scope> getAnnotationProcessorScopes(Project project, String configurationString) {
    Optional<Configuration> configuration = getConfiguration(project, configurationString);
    return configuration.isPresent()
        ? getAnnotationProcessorScopes(project, configuration.get())
        : ImmutableList.of();
  }

  /**
   * Get all the scopes for the specified configuration. Returns one configuration per dependency.
   * Will group auto value and its extensions together into one scope as well.
   *
   * @param project project on which the configuration is defined.
   * @param configuration Configuration which is used to query the deps.
   * @return A list of scopes generated by the configuration.
   */
  public List<Scope> getAnnotationProcessorScopes(Project project, Configuration configuration) {
    ImmutableList.Builder<Scope> scopesBuilder = ImmutableList.builder();

    Map<Dependency, Scope> singleDependencyToScope =
        createProcessorScopes(project, configuration.getAllDependencies());

    Set<Dependency> autoValueDependencies = getAutoValueDependencies(singleDependencyToScope);

    if (autoValueDependencies.size() > 0) {
      Map<Set<Dependency>, Scope> autoValueScopeMap = getAutoValueDependencyToScopeMap();
      if (autoValueScopeMap.size() == 0) {
        throw new IllegalStateException(
            "autoValueConfigurations should be present if adding autoValue dependencies. missing: "
                + autoValueDependencies);
      }
      if (!autoValueScopeMap.containsKey(autoValueDependencies)) {
        throw new IllegalStateException(
            "autoValueConfigurations declared mismatch the autoValue dependencies. missing: "
                + autoValueDependencies + " found: " + autoValueScopeMap.keySet());
      }
      scopesBuilder.add(autoValueScopeMap.get(autoValueDependencies));

      singleDependencyToScope.forEach(
          (dependency, scope) -> {
            if (!autoValueDependencies.contains(dependency)) {
              scopesBuilder.add(scope);
            }
          });
    } else {
      scopesBuilder.addAll(singleDependencyToScope.values());
    }

    return scopesBuilder.build();
  }

  private static ImmutableSet<Dependency> getAutoValueDependencies(
      Map<Dependency, Scope> dependencyToScope) {
    return dependencyToScope
        .entrySet()
        .stream()
        .filter(entry -> isAutoValueScope(entry.getValue()))
        .map(Map.Entry::getKey)
        .collect(ImmutableSet.toImmutableSet());
  }

  private static boolean isAutoValueScope(Scope scope) {
    return scope
        .getExternalDeps()
        .stream()
        .anyMatch(
            dependency -> {
              if (dependency.getGroup().equals(AUTO_VALUE_GROUP)
                  || dependency.getName().startsWith(AUTO_VALUE_NAME)) {
                return true;
              }

              return scope.hasAutoValueExtensions();
            });
  }

  /**
   * Checks if the configuration has any empty annotation processors.
   *
   * @param project project on which the configuration is defined.
   * @param configurationString ConfigurationString which is used to query the deps.
   * @return A boolean whether the configuration has any empty annotation processors.
   */
  @SuppressWarnings("BooleanMethodIsAlwaysInverted")
  public boolean hasEmptyAnnotationProcessors(Project project, String configurationString) {
    Optional<Configuration> configuration = getConfiguration(project, configurationString);
    return configuration.map(config -> hasEmptyAnnotationProcessors(project, config)).orElse(false);
  }

  /**
   * Checks if the configuration has any empty annotation processors.
   *
   * @param project project on which the configuration is defined.
   * @param configuration Configuration which is used to query the deps.
   * @return A boolean whether the configuration has any empty annotation processors.
   */
  public boolean hasEmptyAnnotationProcessors(Project project, Configuration configuration) {
    Map<Dependency, Scope> depToScope =
        createProcessorScopes(project, configuration.getAllDependencies());

    return depToScope
        .values()
        .stream()
        .anyMatch(scope -> scope.getAnnotationProcessors().isEmpty());
  }

  /** Write the buck file for the java_annotation_processor rules. */
  public Map<Path, List<Scope>> getBasePathToExternalDependencyScopeMap() {
    Path rootPath = project.getRootDir().toPath();

    return dependencyToScopeMap
        .values()
        .stream()
        .filter(it -> it.getAnnotationProcessorPlugin().pluginDependency().isPresent())
        .collect(
            Collectors.groupingBy(
                scope ->
                    rootPath.resolve(
                        scope
                            .getAnnotationProcessorPlugin()
                            .pluginDependency()
                            .get()
                            .getTargetPath())));
  }

  public void finalizeProcessors() {
    List<Scope> targetScopes =
        dependencyToScopeMap
            .values()
            .stream()
            .filter(it -> !it.getAnnotationProcessorPlugin().pluginDependency().isPresent())
            .collect(Collectors.toList());

    buckFileManager.writeToBuckFile(
        JavaAnnotationProcessorRuleComposer.compose(targetScopes),
        project.getRootProject().file(processorBuckFile));
  }

  private ImmutableMap<Dependency, Scope> createProcessorScopes(
      Project project, Set<Dependency> dependencies) {

    ImmutableMap.Builder<Dependency, Scope> currentBuilder = new ImmutableMap.Builder<>();

    // Creates a scope using a detached configuration and the given dependency set.
    Function<Set<Dependency>, Scope> computeScope =
        depSet -> {
          Dependency[] depArray = depSet.toArray(new Dependency[0]);
          Configuration detached = project.getConfigurations().detachedConfiguration(depArray);
          return Scope.builder(project).configuration(detached).build();
        };

    // Creates one scope per dependency if not already
    // found and adds it to the current builder.
    dependencies.forEach(
        dependency -> {
          ImmutableSet<Dependency> dependencySet = ImmutableSet.of(dependency);
          Scope scope = dependencyToScopeMap.computeIfAbsent(dependencySet, computeScope);
          currentBuilder.put(dependency, scope);
        });

    return currentBuilder.build();
  }

  private ImmutableMap<Set<Dependency>, Scope> createAutoValueProcessorScopes(
      Project project, Set<String> configurations) {
    ImmutableMap.Builder<Set<Dependency>, Scope> currentBuilder = new ImmutableMap.Builder<>();

    for (String configurationString : configurations) {
      Optional<Configuration> optionalConfiguration =
          getConfiguration(project, configurationString);

      if (optionalConfiguration.isPresent()
          && optionalConfiguration.get().getAllDependencies().size() > 0) {
        Configuration configuration = optionalConfiguration.get();

        ImmutableSet<Dependency> dependencySet =
            ImmutableSet.copyOf(configuration.getAllDependencies());
        Scope scope =
            dependencyToScopeMap.computeIfAbsent(
                dependencySet,
                depSet -> Scope.builder(project).configuration(configuration).build());

        currentBuilder.put(dependencySet, scope);
      }
    }
    return currentBuilder.build();
  }

  private static Optional<Configuration> getConfiguration(
      Project project, String configurationString) {
    Configuration configuration = DependencyUtils.useful(configurationString, project);
    return Optional.ofNullable(configuration);
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -



