/** Walk project references recursively, adding thrift files to the provided list. */
 List<File> getRecursiveThriftFiles(MavenProject project, String outputDirectory, List<File> files)
     throws IOException {
   HashFunction hashFun = Hashing.md5();
   if (dependencyIncludes.contains(project.getArtifactId())) {
     File dir = new File(new File(project.getFile().getParent(), "target"), outputDirectory);
     if (dir.exists()) {
       URI baseDir = getFileURI(dir);
       for (File f : findThriftFilesInDirectory(dir)) {
         URI fileURI = getFileURI(f);
         String relPath = baseDir.relativize(fileURI).getPath();
         File destFolder = getResourcesOutputDirectory();
         destFolder.mkdirs();
         File destFile = new File(destFolder, relPath);
         if (!destFile.exists()
             || (destFile.isFile()
                 && !Files.hash(f, hashFun).equals(Files.hash(destFile, hashFun)))) {
           getLog()
               .info(
                   format("copying %s to %s", f.getCanonicalPath(), destFile.getCanonicalPath()));
           copyFile(f, destFile);
         }
         files.add(destFile);
       }
     }
   }
   Map<String, MavenProject> refs = project.getProjectReferences();
   for (String name : refs.keySet()) {
     getRecursiveThriftFiles(refs.get(name), outputDirectory, files);
   }
   return files;
 }
  /** Executes the mojo. */
  public void execute() throws MojoExecutionException, MojoFailureException {
    try {
      Set<File> thriftFiles = findThriftFiles();

      final File outputDirectory = getOutputDirectory();
      ImmutableSet<File> outputFiles = findGeneratedFilesInDirectory(getOutputDirectory());

      Set<String> compileRoots = new HashSet<String>();
      compileRoots.add("scrooge");

      if (thriftFiles.isEmpty()) {
        getLog().info("No thrift files to compile.");
      } else if (checkStaleness
          && ((lastModified(thriftFiles) + staleMillis) < lastModified(outputFiles))) {
        getLog().info("Generated thrift files up to date, skipping compile.");
        attachFiles(compileRoots);
      } else {
        outputDirectory.mkdirs();

        // Quick fix to fix issues with two mvn installs in a row (ie no clean)
        cleanDirectory(outputDirectory);

        getLog().info(format("compiling thrift files %s with Scrooge", thriftFiles));
        synchronized (lock) {
          ScroogeRunner runner = new ScroogeRunner();
          Map<String, String> thriftNamespaceMap = new HashMap<String, String>();
          for (ThriftNamespaceMapping mapping : thriftNamespaceMappings) {
            thriftNamespaceMap.put(mapping.getFrom(), mapping.getTo());
          }

          // Include thrifts from resource as well.
          Set<File> includes = thriftIncludes;
          includes.add(getResourcesOutputDirectory());

          runner.compile(
              getLog(),
              new File(outputDirectory, "scrooge"),
              thriftFiles,
              includes,
              thriftNamespaceMap,
              language,
              thriftOpts);
        }
        attachFiles(compileRoots);
      }
    } catch (IOException e) {
      throw new MojoExecutionException("An IO error occured", e);
    }
  }
  /** Iterate through dependencies, find those specified in the whitelist */
  private Set<Artifact> findThriftDependencies(Set<String> whitelist) throws IOException {
    Set<Artifact> thriftDependencies = new HashSet<Artifact>();

    Set<Artifact> deps = new HashSet<Artifact>();
    deps.addAll(project.getArtifacts());
    deps.addAll(project.getDependencyArtifacts());

    Map<String, Artifact> depsMap = new HashMap<String, Artifact>();
    for (Artifact dep : deps) {
      depsMap.put(dep.getId(), dep);
    }

    for (Artifact artifact : deps) {
      // This artifact is on the whitelist directly.
      if (whitelist.contains(artifact.getArtifactId())) {
        thriftDependencies.add(artifact);

        // Check if this artifact is being pulled in by an idl jar that's been whitelisted
      } else {
        List<String> depTrail = artifact.getDependencyTrail();
        // depTrail can be null sometimes, which seems like a maven bug
        if (depTrail != null) {
          for (String name : depTrail) {
            Artifact dep = depsMap.get(name);
            if (dep != null
                && "idl".equals(dep.getClassifier())
                && whitelist.contains(dep.getArtifactId())) {
              thriftDependencies.add(artifact);
              break;
            }
          }
        }
      }
    }
    return thriftDependencies;
  }