public void logFilePaths(PrintStream stream, Collection<String> paths) {
   List<String> strings = new ArrayList<String>(paths.size());
   for (String path : paths) {
     strings.add(FileUtil.toSystemIndependentName(getRelativePath(path)));
   }
   logMany(stream, strings);
 }
    public List<ClasspathItemWrapper> dependsOn(final boolean tests) {
      if (tests) {
        if (myTestDependsOn != null) {
          return myTestDependsOn;
        }
      } else if (myDependsOn != null) {
        return myDependsOn;
      }

      final List<ClasspathItemWrapper> result = new ArrayList<ClasspathItemWrapper>();

      for (ClasspathItem cpi : myModule.getClasspath(ClasspathKind.compile(tests))) {
        if (cpi instanceof Module) {
          result.add(getModule(((Module) cpi).getName()));
        } else if (cpi instanceof Library) {
          result.add(new LibraryWrapper((Library) cpi));
        } else {
          result.add(new GenericClasspathItemWrapper(cpi));
        }
      }

      if (tests) {
        myTestDependsOn = result;
      } else {
        myDependsOn = result;
      }

      return result;
    }
    public void write(final BufferedWriter w) {
      RW.writeln(w, "Module:" + myName);

      RW.writeln(w, "SourceProperties:");
      mySource.write(w);

      RW.writeln(w, "TestProperties:");
      myTest.write(w);

      RW.writeln(w, "Excludes:");
      RW.writeln(w, myExcludes, RW.fromString);

      RW.writeln(w, "Libraries:");
      RW.writeln(w, myLibraries);

      RW.writeln(w, "Dependencies:");

      final List<ClasspathItemWrapper> weakened = new ArrayList<ClasspathItemWrapper>();

      for (ClasspathItemWrapper cpiw : dependsOn(false)) {
        weakened.add(weaken(cpiw));
      }

      RW.writeln(w, weakened);

      weakened.clear();

      for (ClasspathItemWrapper cpiw : dependsOn(true)) {
        weakened.add(weaken(cpiw));
      }

      RW.writeln(w, weakened);
    }
    public List<String> getClassPath(final ClasspathKind kind) {
      final List<String> result = new ArrayList<String>();

      result.add(getOutputPath());

      if (kind.isTestsIncluded()) {
        result.add(getTestOutputPath());
      }

      return result;
    }
  public void makeModule(final String modName, final Flags flags) {
    if (modName == null) {
      makeModules(myProject.getModules().values(), flags);
    } else {
      final Module module = myProject.getModules().get(modName);
      final List<Module> list = new ArrayList<Module>();

      if (module == null) {
        System.err.println("Module \"" + modName + "\" not found in project \"" + myRoot + "\"");
        return;
      }

      list.add(module);

      makeModules(list, flags);
    }
  }
  private static void collectAssetDirs(@NotNull AndroidFacet facet, @NotNull List<String> result)
      throws IOException {
    final File assetsDir = facet.getAssetsDir();

    if (assetsDir != null) {
      result.add(assetsDir.getPath());
    }

    for (AndroidFacet depFacet :
        AndroidJpsUtil.getAllAndroidDependencies(facet.getModule(), true)) {
      final File depAssetsDir = depFacet.getAssetsDir();

      if (depAssetsDir != null) {
        result.add(depAssetsDir.getPath());
      }
    }
  }
  @NotNull
  private static String[] collectNativeLibsFolders(@NotNull AndroidFacet facet) throws IOException {
    final List<String> result = new ArrayList<String>();
    final File libsDir = facet.getNativeLibsDir();

    if (libsDir != null) {
      result.add(libsDir.getPath());
    }

    for (AndroidFacet depFacet :
        AndroidJpsUtil.getAllAndroidDependencies(facet.getModule(), true)) {
      final File depLibsDir = depFacet.getNativeLibsDir();
      if (depLibsDir != null) {
        result.add(depLibsDir.getPath());
      }
    }
    return ArrayUtil.toStringArray(result);
  }
  private boolean updateDependencies(
      CompileContext context,
      ModuleChunk chunk,
      List<File> toCompile,
      String moduleOutputPath,
      List<GroovycOSProcessHandler.OutputItem> successfullyCompiled)
      throws IOException {
    final Mappings delta = context.createDelta();
    final List<File> successfullyCompiledFiles = new ArrayList<File>();
    if (!successfullyCompiled.isEmpty()) {

      final Callbacks.Backend callback = delta.getCallback();
      final FileGeneratedEvent generatedEvent = new FileGeneratedEvent();

      for (GroovycOSProcessHandler.OutputItem item : successfullyCompiled) {
        final String sourcePath = FileUtil.toSystemIndependentName(item.sourcePath);
        final String outputPath = FileUtil.toSystemIndependentName(item.outputPath);
        final RootDescriptor moduleAndRoot = context.getModuleAndRoot(new File(sourcePath));
        if (moduleAndRoot != null) {
          final String moduleName = moduleAndRoot.module.getName().toLowerCase(Locale.US);
          context
              .getDataManager()
              .getSourceToOutputMap(moduleName, moduleAndRoot.isTestRoot)
              .appendData(sourcePath, outputPath);
        }
        callback.associate(
            outputPath,
            Callbacks.getDefaultLookup(sourcePath),
            new ClassReader(FileUtil.loadFileBytes(new File(outputPath))));
        successfullyCompiledFiles.add(new File(sourcePath));

        generatedEvent.add(
            moduleOutputPath, FileUtil.getRelativePath(moduleOutputPath, outputPath, '/'));
      }

      context.processMessage(generatedEvent);
    }

    return updateMappings(context, delta, chunk, toCompile, successfullyCompiledFiles);
  }
  @SuppressWarnings("unchecked")
  private static AndroidFileSetState buildCurrentApkBuilderState(
      @NotNull Project project,
      @NotNull String resPackagePath,
      @NotNull String classesDexFilePath,
      @NotNull String[] nativeLibDirs,
      @NotNull String[] sourceRoots,
      @NotNull String[] externalJars,
      boolean release) {
    final List<String> roots = new ArrayList<String>();
    roots.add(resPackagePath);
    roots.add(classesDexFilePath);
    roots.addAll(Arrays.asList(externalJars));

    for (String sourceRootPath : sourceRoots) {
      final List<File> files = new ArrayList<File>();
      AndroidApkBuilder.collectStandardSourceFolderResources(
          new File(sourceRootPath), files, new MyExcludedSourcesFilter(project));
      roots.addAll(AndroidJpsUtil.toPaths(files));
    }

    for (String nativeLibDir : nativeLibDirs) {
      final List<File> files = new ArrayList<File>();
      AndroidApkBuilder.collectNativeLibraries(new File(nativeLibDir), files, !release);
      roots.addAll(AndroidJpsUtil.toPaths(files));
    }

    return new AndroidFileSetState(roots, Condition.TRUE, false);
  }
  public ModuleLevelBuilder.ExitCode build(final CompileContext context, ModuleChunk chunk)
      throws ProjectBuildException {
    try {
      final List<File> toCompile = collectChangedFiles(context, chunk);
      if (toCompile.isEmpty()) {
        return ExitCode.NOTHING_DONE;
      }

      String moduleOutput = getModuleOutput(context, chunk);
      String compilerOutput = getCompilerOutput(moduleOutput);

      final Set<String> toCompilePaths = new LinkedHashSet<String>();
      for (File file : toCompile) {
        toCompilePaths.add(FileUtil.toSystemIndependentName(file.getPath()));
      }

      Map<String, String> class2Src =
          buildClassToSourceMap(chunk, context, toCompilePaths, moduleOutput);

      String ideCharset = chunk.getProject().getProjectCharset();
      String encoding =
          !Comparing.equal(CharsetToolkit.getDefaultSystemCharset().name(), ideCharset)
              ? ideCharset
              : null;
      List<String> patchers = Collections.emptyList(); // todo patchers
      final File tempFile =
          GroovycOSProcessHandler.fillFileWithGroovycParameters(
              compilerOutput,
              toCompilePaths,
              FileUtil.toSystemDependentName(moduleOutput),
              class2Src,
              encoding,
              patchers);

      // todo different outputs in a chunk
      // todo xmx
      final List<String> cmd =
          ExternalProcessUtil.buildJavaCommandLine(
              getJavaExecutable(chunk),
              "org.jetbrains.groovy.compiler.rt.GroovycRunner",
              Collections.<String>emptyList(),
              new ArrayList<String>(generateClasspath(context, chunk)),
              Arrays.asList(
                  "-Xmx384m",
                  "-Dfile.encoding=" + CharsetToolkit.getDefaultSystemCharset().name() /*,
                      "-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5239"*/),
              Arrays.<String>asList(myForStubs ? "stubs" : "groovyc", tempFile.getPath()));

      final Process process = Runtime.getRuntime().exec(ArrayUtil.toStringArray(cmd));
      GroovycOSProcessHandler handler =
          GroovycOSProcessHandler.runGroovyc(
              process,
              new Consumer<String>() {
                public void consume(String s) {
                  context.processMessage(new ProgressMessage(s));
                }
              });

      if (handler.shouldRetry()) {
        if (CHUNK_REBUILD_ORDERED.get(context) != null) {
          CHUNK_REBUILD_ORDERED.set(context, null);
        } else {
          CHUNK_REBUILD_ORDERED.set(context, Boolean.TRUE);
          return ExitCode.CHUNK_REBUILD_REQUIRED;
        }
      }

      if (myForStubs) {
        JavaBuilder.addTempSourcePathRoot(context, new File(compilerOutput));
      }

      for (CompilerMessage message : handler.getCompilerMessages()) {
        context.processMessage(message);
      }
      if (!myForStubs
          && updateDependencies(
              context, chunk, toCompile, moduleOutput, handler.getSuccessfullyCompiled())) {
        return ExitCode.ADDITIONAL_PASS_REQUIRED;
      }
      return ExitCode.OK;
    } catch (Exception e) {
      throw new ProjectBuildException(e);
    }
  }