public BuildStatus build(final Collection<Module> modules, final Flags flags) {
      boolean incremental = flags.incremental();
      final List<ModuleChunk> chunks = myProjectBuilder.getChunks(flags.tests()).getChunkList();

      for (final ModuleChunk c : chunks) {
        final Set<Module> chunkModules = c.getElements();

        if (!DefaultGroovyMethods.intersect(modules, chunkModules).isEmpty()) {
          final Set<String> removedSources = new HashSet<String>();

          if (incremental) {
            final Set<String> chunkSources = new HashSet<String>();
            final Set<String> outdatedSources = new HashSet<String>();

            for (Module m : chunkModules) {
              final ModuleWrapper mw = getModule(m.getName());

              outdatedSources.addAll(mw.getOutdatedFiles(flags.tests()));
              chunkSources.addAll(mw.getSources(flags.tests()));
              removedSources.addAll(mw.getRemovedFiles(flags.tests()));
            }

            final BuildStatus result =
                iterativeCompile(c, chunkSources, outdatedSources, removedSources, flags);

            incremental = result == BuildStatus.INCREMENTAL;

            if (result == BuildStatus.FAILURE) {
              return result;
            }
          } else {
            new Logger(flags) {
              @Override
              public void log(PrintStream stream) {
                stream.println("Compiling chunk " + c.getName() + " non-incrementally.");
              }
            }.log();

            for (Module m : chunkModules) {
              final ModuleWrapper mw = getModule(m.getName());
              removedSources.addAll(flags.tests() ? mw.getRemovedTests() : mw.getRemovedSources());
            }

            final Set<Module> toClean = new HashSet<Module>();

            for (Module m : chunkModules) {
              if (!cleared.contains(m)) {
                toClean.add(m);
              }
            }

            if (!toClean.isEmpty() && !flags.tests()) {
              builder.clearChunk(new ModuleChunk(toClean), null, ProjectWrapper.this);
              cleared.addAll(toClean);
            }

            final Mappings delta = dependencyMapping.createDelta();
            final Callbacks.Backend deltaCallback = delta.getCallback();

            try {
              builder.buildChunk(c, flags.tests(), null, deltaCallback, ProjectWrapper.this);
            } catch (Exception e) {
              e.printStackTrace();
              return BuildStatus.FAILURE;
            }

            final Set<String> allFiles = new HashSet<String>();

            for (Module m : c.getElements()) {
              final ModuleWrapper module = getModule(m.getName());
              affectedFiles.removeAll(module.getSources(flags.tests()));
              allFiles.addAll(module.getSources(flags.tests()));
            }

            final Collection<File> files = new HashSet<File>();

            for (String f : allFiles) {
              files.add(new File(f));
            }

            dependencyMapping.integrate(delta, files, removedSources);

            for (Module m : chunkModules) {
              Reporter.reportBuildSuccess(m, flags.tests());
            }
          }
        }
      }

      return BuildStatus.INCREMENTAL;
    }
    BuildStatus iterativeCompile(
        final ModuleChunk chunk,
        final Set<String> sources,
        final Set<String> outdated,
        final Set<String> removed,
        final Flags flags) {
      final Collection<String> filesToCompile =
          DefaultGroovyMethods.intersect(affectedFiles, sources);

      if (outdated != null) {
        for (String s : outdated) {
          assert (s != null);
        }

        filesToCompile.addAll(outdated);
      }

      filesToCompile.removeAll(compiledFiles);

      if (!filesToCompile.isEmpty() || removed != null) {
        final Set<String> outputFiles = new HashSet<String>();

        for (String f : filesToCompile) {
          final Set<ClassRepr> classes = dependencyMapping.getClasses(f);

          if (classes != null) {
            for (ClassRepr cr : classes) {
              outputFiles.add(cr.getFileName());
            }
          }
        }

        if (removed != null) {
          for (String f : removed) {
            final Set<ClassRepr> classes = dependencyMapping.getClasses(f);
            if (classes != null) {
              for (ClassRepr cr : classes) {
                outputFiles.add(cr.getFileName());
              }
            }
          }
        }

        if (!outputFiles.isEmpty()) {
          new Logger(flags) {
            @Override
            public void log(PrintStream stream) {
              stream.println("Cleaning output files:");
              logFilePaths(stream, outputFiles);
              stream.println("End of files");
            }
          }.log();

          builder.clearChunk(chunk, outputFiles, ProjectWrapper.this);
        }

        final Mappings delta = dependencyMapping.createDelta();
        final Callbacks.Backend deltaBackend = delta.getCallback();

        new Logger(flags) {
          @Override
          public void log(PrintStream stream) {
            stream.println("Compiling files:");
            logFilePaths(stream, filesToCompile);
            stream.println("End of files");
          }
        }.log();

        boolean buildException = false;

        try {
          builder.buildChunk(
              chunk, flags.tests(), filesToCompile, deltaBackend, ProjectWrapper.this);
        } catch (Exception e) {
          e.printStackTrace();
          buildException = true;
        }

        if (!buildException) {
          compiledFiles.addAll(filesToCompile);
          affectedFiles.removeAll(filesToCompile);

          final Collection<File> files = new HashSet<File>();
          final Collection<File> compiled = new HashSet<File>();

          for (String f : filesToCompile) {
            files.add(new File(f));
          }

          for (String f : compiledFiles) {
            compiled.add(new File(f));
          }

          final Collection<File> affected = new HashSet<File>();

          final boolean incremental =
              dependencyMapping.differentiate(delta, removed, files, compiled, affected);

          for (File a : affected) {
            affectedFiles.add(FileUtil.toSystemIndependentName(a.getAbsolutePath()));
          }

          dependencyMapping.integrate(delta, files, removed);

          if (!incremental) {
            affectedFiles.addAll(sources);
            affectedFiles.removeAll(compiledFiles);

            final BuildStatus result = iterativeCompile(chunk, sources, null, null, flags);

            if (result == BuildStatus.FAILURE) {
              return result;
            }

            return BuildStatus.CONSERVATIVE;
          }

          return iterativeCompile(chunk, sources, null, null, flags);
        } else {
          return BuildStatus.FAILURE;
        }
      } else {
        for (Module m : chunk.getElements()) {
          Reporter.reportBuildSuccess(m, flags.tests());
        }
      }

      return BuildStatus.INCREMENTAL;
    }