Skip to content

Commit

Permalink
feat: add util class for pushing to github (#51)
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinWitt committed Feb 2, 2022
1 parent c1ce0b9 commit 28f4aec
Show file tree
Hide file tree
Showing 7 changed files with 407 additions and 46 deletions.
3 changes: 2 additions & 1 deletion code-transformation/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ dependencies {
// This dependency is used by the application.
implementation 'com.google.guava:guava:31.0.1-jre'
// implementation 'fr.inria.gforge.spoon:spoon-core:10.0.1-beta-2'
implementation 'org.eclipse.jgit:org.eclipse.jgit:+'
implementation group: 'org.eclipse.jgit', name: 'org.eclipse.jgit', version: '6.0.0.202111291000-r'
implementation group: 'org.eclipse.jgit', name: 'org.eclipse.jgit.ssh.apache', version: '6.0.0.202111291000-r'
// implementation 'com.github.MartinWitt:Spoon:59fa98b3f8f83b2b566dc876ffabb26ba31ce2e3' // code solver branch
implementation 'fr.inria.gforge.spoon:spoon-core:10.0.1-SNAPSHOT'
implementation 'com.google.flogger:flogger:0.7.4'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public class TransformationEngine {
private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass();
private List<Function<ChangeListener, TransformationProcessor<?>>> processors;
private IPrinting printing;
private ChangeListener changeListener;
public TransformationEngine(List<Function<ChangeListener, TransformationProcessor<?>>> processors) {
this.processors = processors;
}
Expand All @@ -54,6 +55,10 @@ public TransformationEngine() {
PrimitiveToString::new);
}

public void setChangeListener(ChangeListener changeListener) {
this.changeListener = changeListener;
}

public TransformationEngine setPrinting(IPrinting printing) {
this.printing = printing;
return this;
Expand All @@ -69,16 +74,15 @@ public Changelog applyToGivenPath(String path) {
printing = new ChangedTypePrinting(environment.createPrettyPrinter());
}
PrinterCreation.setPrettyPrinter(environment, model);
ChangeListener listener = new ChangeListener();
ProcessingManager pm = new RepeatingProcessingManager(launcher.getFactory(), listener);
addProcessors(pm, listener);
QodanaRefactor refactor = new QodanaRefactor(listener);
refactor.run(Path.of(path));
pm.addProcessor(refactor);
if (changeListener == null) {
changeListener = new ChangeListener();
}
ProcessingManager pm = new RepeatingProcessingManager(launcher.getFactory(), changeListener);
addProcessors(pm, changeListener);
pm.process(model.getAllTypes());
Collection<CtType<?>> newTypes = model.getAllTypes();
printing.printChangedTypes(listener, newTypes);
return listener.getChangelog();
printing.printChangedTypes(changeListener, newTypes);
return changeListener.getChangelog();
}

protected void addInput(String path, Launcher launcher) {
Expand All @@ -99,13 +103,15 @@ public Changelog applyToGivenPath(String path, String typeName) {
if (printing == null) {
printing = new ChangedTypePrinting(environment.createPrettyPrinter());
}
ChangeListener listener = new ChangeListener();
ProcessingManager pm = new RepeatingProcessingManager(launcher.getFactory(), listener);
if (changeListener == null) {
changeListener = new ChangeListener();
}
ProcessingManager pm = new RepeatingProcessingManager(launcher.getFactory(), changeListener);
Collection<CtType<?>> newTypes = getTypesWithName(typeName, model);
addProcessors(pm, listener);
addProcessors(pm, changeListener);
pm.process(newTypes);
printing.printChangedTypes(listener, newTypes);
return listener.getChangelog();
printing.printChangedTypes(changeListener, newTypes);
return changeListener.getChangelog();
}

private static List<CtType<?>> getTypesWithName(String typeName, CtModel model) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ public class QodanaRefactor extends TransformationProcessor<CtType<?>> {
private Map<String, Function<Result, AbstractRefactoring>> ruleParser;
private List<AbstractRefactoring> refactorings;

private QodanaRefactor(Builder builder) {
super(builder.listener);
refactorings = new ArrayList<>();
this.listener = builder.listener;
this.ruleParser = builder.ruleParser;
}

public QodanaRefactor(ChangeListener listener) {
super(listener);
this.listener = listener;
Expand All @@ -50,7 +57,23 @@ public QodanaRefactor(ChangeListener listener) {
* @param projectRoot The root of the project which should be analysed.
*/
public void run(Path projectRoot) {
List<Result> results = new QodanaRunner().runQodana(projectRoot);
QodanaRunner runner = new QodanaRunner.Builder().build();
List<Result> results = runner.runQodana(projectRoot);
for (Result result : results) {
var parser = ruleParser.get(result.getRuleId());
if (parser != null) {
refactorings.add(parser.apply(result));
}
}
}

/**
* Analyses the source code in the given source root
* @param projectRoot The root of the project which should be analysed.
*/
public void run(Path projectRoot, String srcPath) {
QodanaRunner runner = new QodanaRunner.Builder().withSourceFileRoot(srcPath).build();
List<Result> results = runner.runQodana(projectRoot);
for (Result result : results) {
var parser = ruleParser.get(result.getRuleId());
if (parser != null) {
Expand All @@ -65,4 +88,50 @@ public void process(CtType<?> type) {
refactoring.refactor(listener, type);
}
}

public static class Builder {

private ChangeListener listener;
private Map<String, Function<Result, AbstractRefactoring>> ruleParser = new HashMap<>();
public Builder(ChangeListener listener) {
this.listener = listener;
}

public Builder withUnnecessaryReturn() {
ruleParser.put("UnnecessaryReturn", UnnecessaryReturn::new);
return this;
}

public Builder withUnnecessaryToStringCall() {
ruleParser.put("UnnecessaryToStringCall", UnnecessaryToStringCall::new);
return this;
}

public Builder withNonProtectedConstructorInAbstractClass() {
ruleParser.put("NonProtectedConstructorInAbstractClass", NonProtectedConstructorInAbstractClass::new);
return this;
}

public Builder withUnnecessaryInterfaceModifier() {
ruleParser.put("UnnecessaryInterfaceModifier", UnnecessaryInterfaceModifier::new);
return this;
}

public Builder withParameterNameDiffersFromOverriddenParameter() {
ruleParser.put("ParameterNameDiffersFromOverriddenParameter",
ParameterNameDiffersFromOverriddenParameter::new);
return this;
}

public Builder withMethodMayBeStatic() {
ruleParser.put("MethodMayBeStatic", MethodMayBeStatic::new);
return this;
}

public QodanaRefactor build() {
return new QodanaRefactor(this);
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -38,25 +38,27 @@

class QodanaRunner {

private static final String RESULTS_PATH = "./.results/";
private static final String CACHE_PATH = "./.laughing/";
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private String qodanaImageName = "jetbrains/qodana-jvm-community:2021.3";
private String resultPathString = RESULTS_PATH + "qodana.sarif.json";
private String resultFolder;
private String cacheFolder;
private String qodanaImageName;
private String resultPathString;
private boolean removeResultDir = true;
private String sourceFileRoot = "./src/main/java";

private QodanaRunner(Builder builder) {
this.resultFolder = builder.resultFolder;
this.cacheFolder = builder.cacheFolder;
this.qodanaImageName = builder.qodanaImageName;
this.resultPathString = builder.resultPathString;
this.removeResultDir = builder.removeResultDir;
this.sourceFileRoot = builder.sourceFileRoot;
}

public List<Result> runQodana(Path sourceRoot) {
sourceRoot = fixWindowsPath(sourceRoot);
logger.atInfo().log("Running Qodana on %s", sourceRoot);
try {
sourceRoot = fixWindowsPath(sourceRoot);
File qodanaRules = new File(this.getClass().getResource("/qodana.yml").toURI());
File copyQodanaRules = new File(sourceRoot.toString(), "qodana.yaml");
Files.writeString(copyQodanaRules.toPath(), Files.readString(qodanaRules.toPath()),
StandardOpenOption.CREATE);

}
catch (URISyntaxException | IOException e1) {
logger.atSevere().withCause(e1).log("Could not write qodana.yaml");
}
copyQodanaRules(sourceRoot);
DockerClientConfig standard = DefaultDockerClientConfig.createDefaultConfigBuilder().build();
DockerHttpClient httpClient = createHttpClient(standard);
try (DockerClient dockerClient = DockerClientImpl.getInstance(standard, httpClient);) {
Expand All @@ -66,14 +68,7 @@ public List<Result> runQodana(Path sourceRoot) {
}
Optional<Image> qodana = findQodanaImage(dockerClient);
if (qodana.isPresent()) {
HostConfig hostConfig = createHostConfig(sourceRoot);
CreateContainerResponse container = createQodanaContainer(dockerClient, qodana, hostConfig);
List<Result> results = startQodanaContainer(dockerClient, container);
// cleanUpContainer(dockerClient, container);
FileUtils.deleteDirectory(Path.of(RESULTS_PATH).toFile());
FileUtils.deleteDirectory(Path.of(CACHE_PATH).toFile());
Files.deleteIfExists(Path.of(sourceRoot.toString(), "qodana.yaml"));
return results;
return executeQodana(sourceRoot, dockerClient, qodana);
}
}
catch (Exception e) {
Expand All @@ -82,8 +77,42 @@ public List<Result> runQodana(Path sourceRoot) {
return List.of();
}

private void cleanUpContainer(DockerClient dockerClient, CreateContainerResponse container) {
dockerClient.removeContainerCmd(container.getId()).withRemoveVolumes(true).exec();
private List<Result> executeQodana(Path sourceRoot, DockerClient dockerClient, Optional<Image> qodana)
throws InterruptedException, IOException {
HostConfig hostConfig = createHostConfig(sourceRoot);
CreateContainerResponse container = createQodanaContainer(dockerClient, qodana.get(), hostConfig);
List<Result> results = startQodanaContainer(dockerClient, container);
cleanCaches(sourceRoot);
return results;
}

private void cleanCaches(Path sourceRoot) throws IOException {
if (removeResultDir) {
FileUtils.deleteDirectory(stringToFile(resultFolder));
}
FileUtils.deleteDirectory(stringToFile(cacheFolder));
Files.deleteIfExists(Path.of(sourceRoot.toString(), "qodana.yaml"));
}

/**
* Converts the given path as string to a file object
* @param path the path as string
* @return the file object
*/
private File stringToFile(String path) {
return Path.of(path).toFile();
}

private void copyQodanaRules(Path sourceRoot) {
try {
File qodanaRules = new File(this.getClass().getResource("/qodana.yml").toURI());
File copyQodanaRules = new File(sourceRoot.toString(), "qodana.yaml");
Files.writeString(copyQodanaRules.toPath(), Files.readString(qodanaRules.toPath()),
StandardOpenOption.CREATE);
}
catch (URISyntaxException | IOException e) {
logger.atSevere().withCause(e).log("Could not write qodana.yaml");
}
}

private List<Result> startQodanaContainer(DockerClient dockerClient, CreateContainerResponse container)
Expand All @@ -109,13 +138,13 @@ public void onNext(WaitResponse object) {
return results;
}

private CreateContainerResponse createQodanaContainer(DockerClient dockerClient, Optional<Image> qodana,
private CreateContainerResponse createQodanaContainer(DockerClient dockerClient, Image qodana,
HostConfig hostConfig) {
return dockerClient.createContainerCmd(qodana.get().getId())
return dockerClient.createContainerCmd(qodana.getId())
.withHostConfig(hostConfig)
.withAttachStderr(true)
.withAttachStdout(true)
.withCmd("-d", "./src/main/java")
.withCmd("-d", sourceFileRoot)
.exec();
}

Expand All @@ -124,8 +153,8 @@ private HostConfig createHostConfig(Path sourceRoot) {
Volume targetFile = new Volume("/data/results/");
Volume cacheDir = new Volume("/data/cache/");
Bind bind = new Bind(sourceRoot.toFile().getAbsolutePath(), sourceFile);
Bind resultsBind = new Bind(new File(RESULTS_PATH).getAbsolutePath(), targetFile);
Bind cacheBind = new Bind(new File(CACHE_PATH).getAbsolutePath(), cacheDir);
Bind resultsBind = new Bind(new File(resultFolder).getAbsolutePath(), targetFile);
Bind cacheBind = new Bind(new File(cacheFolder).getAbsolutePath(), cacheDir);
return HostConfig.newHostConfig().withBinds(bind, cacheBind, resultsBind).withAutoRemove(true);
}

Expand Down Expand Up @@ -162,4 +191,45 @@ private List<Result> parseSarif(Path resultPath) throws IOException {
SarifSchema210 sarif = mapper.readValue(reader, SarifSchema210.class);
return sarif.getRuns().get(0).getResults();
}

static class Builder {

private String resultFolder = "./.results/";
private String cacheFolder = "./.laughing/";
private String qodanaImageName = "jetbrains/qodana-jvm-community:2021.3";
private String resultPathString = resultFolder + "qodana.sarif.json";
private boolean removeResultDir = true;
private String sourceFileRoot = "./src/main/java";

public Builder withResultFolder(String resultFolder) {
this.resultFolder = resultFolder;
this.resultPathString = resultFolder + "qodana.sarif.json";
return this;
}

public Builder withCacheFolder(String cacheFolder) {
this.cacheFolder = cacheFolder;
return this;
}

public Builder withQodanaImageName(String qodanaImageName) {
this.qodanaImageName = qodanaImageName;
return this;
}

public Builder withRemoveResultDir(boolean removeResultDir) {
this.removeResultDir = removeResultDir;
return this;
}

public Builder withSourceFileRoot(String sourceFileRoot) {
this.sourceFileRoot = sourceFileRoot;
return this;
}

public QodanaRunner build() {
return new QodanaRunner(this);
}

}
}
Loading

0 comments on commit 28f4aec

Please sign in to comment.