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;
    }
  private static List<String> generateClasspath(CompileContext context, ModuleChunk chunk) {
    final Set<String> cp = new LinkedHashSet<String>();
    // groovy_rt.jar
    // IMPORTANT! must be the first in classpath
    cp.add(ClasspathBootstrap.getResourcePath(GroovyCompilerWrapper.class).getPath());

    for (File file :
        context
            .getProjectPaths()
            .getClasspathFiles(chunk, ClasspathKind.compile(context.isCompilingTests()), false)) {
      cp.add(FileUtil.toCanonicalPath(file.getPath()));
    }
    for (File file :
        context
            .getProjectPaths()
            .getClasspathFiles(chunk, ClasspathKind.runtime(context.isCompilingTests()), false)) {
      cp.add(FileUtil.toCanonicalPath(file.getPath()));
    }
    return new ArrayList<String>(cp);
  }
  public void makeModules(final Collection<Module> initial, final Flags flags) {
    if (myHistory == null && !flags.tests()) {
      clean();
    }

    new Logger(flags) {
      @Override
      public void log(final PrintStream stream) {
        stream.println("Request to make modules:");
        logMany(stream, initial);
        stream.println("End of request");
      }
    }.log();

    final ClasspathKind kind = ClasspathKind.compile(flags.tests());

    final Set<Module> modules = new HashSet<Module>();
    final Set<String> marked = new HashSet<String>();
    final Map<String, Boolean> visited = new HashMap<String, Boolean>();
    final Set<String> frontier = new HashSet<String>();

    final Map<String, Set<String>> reversedDependencies = new HashMap<String, Set<String>>();
    final DotPrinter printer = new DotPrinter(flags.logStream());

    printer.header();

    for (Module m : myProject.getModules().values()) {
      final String mName = m.getName();

      printer.node(mName);

      for (ClasspathItem cpi : m.getClasspath(kind)) {
        if (cpi instanceof Module) {
          final String name = ((Module) cpi).getName();

          printer.edge(name, mName);

          Set<String> sm = reversedDependencies.get(name);

          if (sm == null) {
            sm = new HashSet<String>();
            reversedDependencies.put(name, sm);
          }

          sm.add(mName);
        }
      }
    }

    printer.footer();

    // Building "upper" subgraph

    printer.header();

    new Object() {
      public void run(final Collection<Module> initial) {
        if (initial == null) return;

        for (Module module : initial) {

          final String mName = module.getName();

          if (marked.contains(mName)) continue;

          printer.node(mName);

          final List<Module> dep = new ArrayList<Module>();

          for (ClasspathItem cpi : module.getClasspath(kind)) {
            if (cpi instanceof Module && !marked.contains(((Module) cpi).getName())) {
              printer.edge(((Module) cpi).getName(), mName);
              dep.add((Module) cpi);
            }
          }

          if (dep.size() == 0) {
            frontier.add(mName);
          }

          marked.add(mName);

          run(dep);
        }
      }
    }.run(initial);

    printer.footer();

    // Traversing "upper" subgraph and collecting outdated modules and their descendants
    new Object() {
      public void run(final Collection<String> initial, final boolean force) {
        if (initial == null) return;

        for (String moduleName : initial) {
          if (!marked.contains(moduleName)) continue;

          final Boolean property = visited.get(moduleName);

          if (property == null || !property && force) {
            final boolean outdated = getModule(moduleName).isOutdated(flags.tests(), myHistory);

            if (force || outdated) {
              visited.put(moduleName, true);
              modules.add(myProject.getModules().get(moduleName));

              run(reversedDependencies.get(moduleName), true);
            } else {
              if (property == null) {
                visited.put(moduleName, false);
              }
              run(reversedDependencies.get(moduleName), false);
            }
          }
        }
      }
    }.run(frontier, flags.force());

    new Logger(flags) {
      @Override
      public void log(PrintStream stream) {
        stream.println("Propagated modules:");
        logMany(stream, modules);
        stream.println("End of propagated");
      }
    }.log();

    if (modules.size() == 0 && !flags.force()) {
      System.out.println("All requested modules are up-to-date.");
      return;
    }

    final BusyBeaver beaver = new BusyBeaver(myProjectBuilder);

    myProjectBuilder.buildStart();

    if (flags.tests()) {
      beaver.build(
          modules,
          new Flags() {
            public boolean tests() {
              return false;
            }

            public boolean incremental() {
              return flags.incremental();
            }

            public boolean force() {
              return flags.force();
            }

            public PrintStream logStream() {
              return flags.logStream();
            }
          });
    }

    beaver.build(modules, flags);

    myProjectBuilder.buildStop();

    for (Module mod : modules) {
      getModule(mod.getName()).updateOutputStatus();
    }
  }
  public Builder.ExitCode build(final CompileContext context, ModuleChunk chunk)
      throws ProjectBuildException {
    ExitCode exitCode = ExitCode.OK;
    final Map<File, Module> toCompile = new HashMap<File, Module>();
    try {
      context.processFilesToRecompile(
          chunk,
          new FileProcessor() {
            @Override
            public boolean apply(Module module, File file, String sourceRoot) throws Exception {
              final String path = file.getPath();
              if (isGroovyFile(path)) { // todo file type check
                toCompile.put(file, module);
              }
              return true;
            }
          });

      if (toCompile.isEmpty()) {
        return exitCode;
      }

      final Set<String> cp = new LinkedHashSet<String>();
      // groovy_rt.jar
      // IMPORTANT! must be the first in classpath
      cp.add(ClasspathBootstrap.getResourcePath(GroovyCompilerWrapper.class).getPath());

      for (File file :
          context
              .getProjectPaths()
              .getClasspathFiles(chunk, ClasspathKind.compile(context.isCompilingTests()), false)) {
        cp.add(FileUtil.toCanonicalPath(file.getPath()));
      }
      for (File file :
          context
              .getProjectPaths()
              .getClasspathFiles(chunk, ClasspathKind.runtime(context.isCompilingTests()), false)) {
        cp.add(FileUtil.toCanonicalPath(file.getPath()));
      }

      final File tempFile = FileUtil.createTempFile("ideaGroovyToCompile", ".txt", true);
      final Module representativeModule = chunk.getModules().iterator().next();
      File moduleOutputDir =
          context
              .getProjectPaths()
              .getModuleOutputDir(representativeModule, context.isCompilingTests());
      final File dir =
          myForStubs
              ? FileUtil.createTempDirectory(/*new File("/tmp/stubs/"), */ "groovyStubs", null)
              : moduleOutputDir;
      assert dir != null;

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

      String moduleOutputPath = FileUtil.toCanonicalPath(moduleOutputDir.getPath());
      if (!moduleOutputPath.endsWith("/")) {
        moduleOutputPath += "/";
      }
      Map<String, String> class2Src =
          buildClassToSourceMap(chunk, context, toCompilePaths, moduleOutputPath);

      String encoding = "UTF-8"; // todo encoding
      List<String> patchers = Collections.emptyList(); // todo patchers
      GroovycOSProcessHandler.fillFileWithGroovycParameters(
          tempFile,
          FileUtil.toCanonicalPath(dir.getPath()),
          toCompilePaths,
          FileUtil.toSystemDependentName(moduleOutputPath),
          class2Src,
          encoding,
          patchers);

      if (myForStubs) {
        JavaBuilder.addTempSourcePathRoot(context, dir);
      }

      // todo CompilerUtil.addLocaleOptions()
      // todo different outputs in a chunk
      // todo module jdk path
      final List<String> cmd =
          ExternalProcessUtil.buildJavaCommandLine(
              SystemProperties.getJavaHome() + "/bin/java",
              "org.jetbrains.groovy.compiler.rt.GroovycRunner",
              Collections.<String>emptyList(),
              new ArrayList<String>(cp),
              Arrays.asList(
                  "-Xmx384m" /*, "-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5858"*/),
              Arrays.<String>asList(myForStubs ? "stubs" : "groovyc", tempFile.getPath()));

      deleteCorrespondingOutputFiles(context, toCompile);

      List<GroovycOSProcessHandler.OutputItem> successfullyCompiled = Collections.emptyList();
      try {
        final Process process = Runtime.getRuntime().exec(cmd.toArray(new String[cmd.size()]));
        GroovycOSProcessHandler handler =
            new GroovycOSProcessHandler(process, null) {
              @Override
              protected void updateStatus(@Nullable String status) {
                context.processMessage(
                    new ProgressMessage(status == null ? GROOVY_COMPILER_IN_OPERATION : status));
              }
            };
        handler.startNotify();
        handler.waitFor();

        successfullyCompiled = handler.getSuccessfullyCompiled();

        final List<CompilerMessage> messages = handler.getCompilerMessages();
        for (CompilerMessage message : messages) {
          context.processMessage(message);
        }

        boolean hasMessages = !messages.isEmpty();

        final StringBuffer unparsedBuffer = handler.getStdErr();
        if (unparsedBuffer.length() != 0) {
          context.processMessage(
              new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.INFO, unparsedBuffer.toString()));
        }

        final int exitValue = handler.getProcess().exitValue();
        if (!hasMessages && exitValue != 0) {
          context.processMessage(
              new CompilerMessage(
                  BUILDER_NAME,
                  BuildMessage.Kind.ERROR,
                  "Internal groovyc error: code " + exitValue));
        }
      } finally {
        if (!myForStubs) {
          final Mappings delta = context.createDelta();
          final List<File> successfullyCompiledFiles = new ArrayList<File>();
          if (!successfullyCompiled.isEmpty()) {
            final Callbacks.Backend callback = delta.getCallback();

            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));
            }
          }

          final boolean needSecondPass =
              updateMappings(context, delta, chunk, toCompile.keySet(), successfullyCompiledFiles);
          if (needSecondPass) {
            exitCode = ExitCode.ADDITIONAL_PASS_REQUIRED;
          }
        }
      }

      return exitCode;
    } catch (Exception e) {
      throw new ProjectBuildException(e);
    }
  }