All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.oliviercailloux.grade.MavenCodeHelper Maven / Gradle / Ivy

The newest version!
package io.github.oliviercailloux.grade;

import static com.google.common.base.Verify.verify;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import io.github.oliviercailloux.jaris.collections.CollectionUtils;
import io.github.oliviercailloux.jaris.exceptions.CheckedStream;
import io.github.oliviercailloux.jaris.io.PathUtils;
import io.github.oliviercailloux.javagrade.JavaGradeUtils;
import io.github.oliviercailloux.javagrade.bytecode.Compiler.CompilationResult;
import io.github.oliviercailloux.javagrade.bytecode.Compiler.CompilationResultExt;
import io.github.oliviercailloux.javagrade.bytecode.MyCompiler;
import io.github.oliviercailloux.utils.Utils;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Set;
import java.util.function.Function;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MavenCodeHelper {
  @SuppressWarnings("unused")
  private static final Logger LOGGER = LoggerFactory.getLogger(MavenCodeHelper.class);

  public static enum WarningsBehavior {
    DO_NOT_PENALIZE, PENALIZE_WARNINGS_AND_NOT_SUPPRESSED, PENALIZE_WARNINGS_AND_SUPPRESS;

    public boolean penalizeWarnings() {
      return ImmutableSet.of(PENALIZE_WARNINGS_AND_NOT_SUPPRESSED, PENALIZE_WARNINGS_AND_SUPPRESS)
          .contains(this);
    }
  }

  public static  MavenCodeHelper penal(WarningsBehavior w) {
    return new MavenCodeHelper<>(w, new BasicCompiler());
  }

  public static  MavenCodeHelper basic() {
    return new MavenCodeHelper<>(WarningsBehavior.PENALIZE_WARNINGS_AND_SUPPRESS,
        new BasicCompiler());
  }

  public static  MavenCodeHelper complex(boolean considerSuppressed,
      MyCompiler compiler) {
    return new MavenCodeHelper<>(
        considerSuppressed ? WarningsBehavior.PENALIZE_WARNINGS_AND_SUPPRESS
            : WarningsBehavior.PENALIZE_WARNINGS_AND_NOT_SUPPRESSED,
        compiler);
  }

  public static class BasicCompiler implements MyCompiler {

    @Override
    public CompilationResultExt compile(Path compiledDir, Set javaPaths) throws IOException {
      final CompilationResult eclipseResult = io.github.oliviercailloux.javagrade.bytecode.Compiler
          .eclipseCompileUsingOurClasspath(javaPaths, compiledDir);
      final Pattern pathPattern = Pattern.compile("/tmp/sources[0-9]*/");
      final String eclipseStr = pathPattern.matcher(eclipseResult.err).replaceAll("/…/");
      final int nbSuppressed = (int) CheckedStream.wrapping(javaPaths.stream())
          .map(p -> Files.readString(p))
          .flatMap(s -> Pattern.compile("@SuppressWarnings").matcher(s).results()).count();
      final CompilationResultExt transformedResult =
          io.github.oliviercailloux.javagrade.bytecode.Compiler.CompilationResultExt.given(
              eclipseResult.compiled, eclipseResult.out, eclipseStr, nbSuppressed, compiledDir,
              javaPaths);
      return transformedResult;
    }
  }

  public static final Criterion WARNING_CRITERION = Criterion.given("Warnings");
  public static final Criterion CODE_CRITERION = Criterion.given("Code");
  private final MyCompiler basicCompiler;
  private WarningsBehavior waB;

  MavenCodeHelper(WarningsBehavior w, MyCompiler basicCompiler) {
    this.waB = w;
    this.basicCompiler = basicCompiler;
  }

  public CompilationResultExt compile(Path pomDirectory) throws IOException, X {
    final Path compiledDir = Utils.getTempUniqueDirectory("compile");
    final Path srcDir;
    final boolean hasPom = Files.exists(pomDirectory.resolve("pom.xml"));
    if (hasPom) {
      srcDir = pomDirectory.resolve("src/main/java/");
    } else {
      // srcDir = projectDirectory.resolve("src/main/java/");
      srcDir = pomDirectory;
    }
    final ImmutableSet javaPaths =
        Files.exists(srcDir) ? PathUtils.getMatchingChildren(srcDir,
            p -> String.valueOf(p.getFileName()).endsWith(".java")) : ImmutableSet.of();
    final CompilationResultExt result = basicCompiler.compile(compiledDir, javaPaths);
    if (javaPaths.isEmpty()) {
      LOGGER.debug("No java files at {}.", srcDir);
    }
    return result;
  }

  public MarksTree grade(CompilationResultExt result, CodeGrader grader) throws X {
    final MarksTree projectGrade;
    if (result.countErrors() > 0) {
      projectGrade = Mark.zero(result.err);
    } else if (result.javaPaths.isEmpty()) {
      projectGrade = Mark.zero("No java files found");
    } else {
      final MarksTree codeGrade =
          JavaGradeUtils.markSecurely(result.compiledDir, grader::gradeCode);
      if (waB.penalizeWarnings()) {
        final Mark weightingMark;
        {
          final int nbCountedSW = (waB == WarningsBehavior.PENALIZE_WARNINGS_AND_SUPPRESS)
              ? result.nbSuppressWarnings : 0;
          final String comment;
          {
            final ImmutableSet.Builder commentsBuilder = ImmutableSet.builder();
            if (result.countWarnings() > 0) {
              commentsBuilder.add(result.err);
            }
            if (nbCountedSW > 0) {
              commentsBuilder.add("Found " + result.nbSuppressWarnings + " suppressed warnings");
            }
            comment = commentsBuilder.build().stream().collect(Collectors.joining(". "));
          }
          final double penalty = Math.min((result.countWarnings() + nbCountedSW) * 0.05d, 0.1d);
          final double weightingScore = 1d - penalty;
          weightingMark = Mark.given(weightingScore, comment);
        }
        projectGrade = MarksTree.composite(
            ImmutableMap.of(WARNING_CRITERION, weightingMark, CODE_CRITERION, codeGrade));
      } else {
        projectGrade = codeGrade;
      }
    }
    return projectGrade;
  }

  public GradeAggregator getAggregator(CodeGrader grader) {
    if (waB.penalizeWarnings()) {
      return GradeAggregator.min(GradeAggregator.parametric(CODE_CRITERION, WARNING_CRITERION,
          grader.getCodeAggregator()));
    }
    return GradeAggregator.min(grader.getCodeAggregator());
  }

  public static ImmutableSet possibleDirs(Path projectPath) throws IOException {
    final ImmutableSet poms =
        PathUtils.getMatchingChildren(projectPath, p -> p.endsWith("pom.xml"));
    LOGGER.debug("Poms: {}.", poms);
    final ImmutableSet pomsWithJava;
    pomsWithJava = CheckedStream.wrapping(poms.stream())
        .filter(p -> !PathUtils
            .getMatchingChildren(p, s -> String.valueOf(s.getFileName()).endsWith(".java"))
            .isEmpty())
        .collect(ImmutableSet.toImmutableSet());
    LOGGER.debug("Poms with java: {}.", pomsWithJava);
    final ImmutableSet possibleDirs;
    if (pomsWithJava.isEmpty()) {
      possibleDirs = ImmutableSet.of(projectPath);
    } else {
      possibleDirs =
          pomsWithJava.stream().map(Path::getParent).collect(ImmutableSet.toImmutableSet());
    }
    return possibleDirs;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy