private static String ensureCorrectOutput(
      ModuleChunk chunk,
      GroovycOutputParser.OutputItem item,
      Map<ModuleBuildTarget, String> generationOutputs,
      String compilerOutput,
      @NotNull ModuleBuildTarget srcTarget)
      throws IOException {
    if (chunk.getModules().size() > 1 && !srcTarget.equals(chunk.representativeTarget())) {
      File output = new File(item.outputPath);

      String srcTargetOutput = generationOutputs.get(srcTarget);
      if (srcTargetOutput == null) {
        LOG.info(
            "No output for "
                + srcTarget
                + "; outputs="
                + generationOutputs
                + "; targets = "
                + chunk.getTargets());
        return item.outputPath;
      }

      // todo honor package prefixes
      File correctRoot = new File(srcTargetOutput);
      File correctOutput =
          new File(correctRoot, FileUtil.getRelativePath(new File(compilerOutput), output));

      FileUtil.rename(output, correctOutput);
      return correctOutput.getPath();
    }
    return item.outputPath;
  }
 private static Map<File, Set<File>> buildOutputDirectoriesMap(
     CompileContext context, ModuleChunk chunk) {
   final Map<File, Set<File>> map = new THashMap<File, Set<File>>(FileUtil.FILE_HASHING_STRATEGY);
   for (ModuleBuildTarget target : chunk.getTargets()) {
     final File outputDir = target.getOutputDir();
     if (outputDir == null) {
       continue;
     }
     final Set<File> roots = new THashSet<File>(FileUtil.FILE_HASHING_STRATEGY);
     for (JavaSourceRootDescriptor descriptor :
         context.getProjectDescriptor().getBuildRootIndex().getTargetRoots(target, context)) {
       roots.add(descriptor.root);
     }
     map.put(outputDir, roots);
   }
   return map;
 }
 private static Map<ModuleBuildTarget, String> getStubGenerationOutputs(
     ModuleChunk chunk, CompileContext context) throws IOException {
   Map<ModuleBuildTarget, String> generationOutputs = new HashMap<ModuleBuildTarget, String>();
   File commonRoot = getStubRoot(context);
   for (ModuleBuildTarget target : chunk.getTargets()) {
     File targetRoot =
         new File(
             commonRoot,
             target.getModule().getName() + File.separator + target.getTargetType().getTypeId());
     if (targetRoot.exists() && !FileUtil.deleteWithRenaming(targetRoot)) {
       throw new IOException("External make cannot clean " + targetRoot.getPath());
     }
     if (!targetRoot.mkdirs()) {
       throw new IOException("External make cannot create " + targetRoot.getPath());
     }
     generationOutputs.put(target, targetRoot.getPath());
   }
   return generationOutputs;
 }
 @Nullable
 public static Map<ModuleBuildTarget, String> getCanonicalModuleOutputs(
     CompileContext context, ModuleChunk chunk, Builder builder) {
   Map<ModuleBuildTarget, String> finalOutputs = new LinkedHashMap<ModuleBuildTarget, String>();
   for (ModuleBuildTarget target : chunk.getTargets()) {
     File moduleOutputDir = target.getOutputDir();
     if (moduleOutputDir == null) {
       context.processMessage(
           new CompilerMessage(
               builder.getPresentableName(),
               BuildMessage.Kind.ERROR,
               "Output directory not specified for module " + target.getModule().getName()));
       return null;
     }
     //noinspection ResultOfMethodCallIgnored
     moduleOutputDir.mkdirs();
     String moduleOutputPath = FileUtil.toCanonicalPath(moduleOutputDir.getPath());
     assert moduleOutputPath != null;
     finalOutputs.put(
         target, moduleOutputPath.endsWith("/") ? moduleOutputPath : moduleOutputPath + "/");
   }
   return finalOutputs;
 }