Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added automatic mode selection #2168

Open
wants to merge 9 commits into
base: develop
Choose a base branch
from
94 changes: 34 additions & 60 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,86 +80,59 @@ The language can either be set with the -l parameter or as a subcommand (`jplag
Language-specific arguments can be set when using the subcommand. A list of language-specific options can be obtained by requesting the help page of a subcommand (e.g., `jplag java —h`).

```
Parameter descriptions:
Parameter descriptions:
[root-dirs[,root-dirs...]...]
Root-directory with submissions to check for
plagiarism. If mode is set to VIEW, this parameter
can be used to specify a file to open. In that case
only a single file may be specified.
Root-directory with submissions to check for plagiarism. If mode is set to VIEW, this parameter can be used to specify a report file to open. In that
case only a single file may be specified.
-bc, --bc, --base-code=<baseCode>
Path to the base code directory (common framework used
in all submissions).
-l, --language=<language>
Select the language of the submissions (default: java).
See subcommands below.
-M, --mode=<{RUN, VIEW, RUN_AND_VIEW}>
The mode of JPlag. If VIEW is chosen, you can specify a
result file to display. One of: RUN, VIEW,
RUN_AND_VIEW (default: null)
-n, --shown-comparisons=<shownComparisons>
The maximum number of comparisons that will be shown in
the generated report, if set to -1 all comparisons
will be shown (default: 2500)
Path to the base code directory (common framework used in all submissions).
-l, --language=<language>
Select the language of the submissions (default: java). See subcommands below.
-M, --mode=<{RUN, VIEW, RUN_AND_VIEW, AUTO}>
The mode of JPlag. One of: RUN, VIEW, RUN_AND_VIEW, AUTO (default: null). If VIEW is chosen, you can optionally specify a path to an existing report.
-n, --shown-comparisons=<shownComparisons>
The maximum number of comparisons that will be shown in the generated report, if set to -1 all comparisons will be shown (default: 2500)
-new, --new=<newDirectories>[,<newDirectories>...]
Root-directories with submissions to check for
plagiarism (same as root).
--normalize Activate the normalization of tokens. Supported for
languages: Java, C++.
Root-directories with submissions to check for plagiarism (same as root).
--normalize Activate the normalization of tokens. Supported for languages: Java, C++.
-old, --old=<oldDirectories>[,<oldDirectories>...]
Root-directories with prior submissions to compare
against.
-r, --result-file=<resultFile>
Name of the file in which the comparison results will
be stored (default: results). Missing .zip endings
will be automatically added.
-t, --min-tokens=<minTokenMatch>
Tunes the comparison sensitivity by adjusting the
minimum token required to be counted as a matching
section. A smaller value increases the sensitivity
but might lead to more false-positives.
Root-directories with prior submissions to compare against.
-r, --result-file=<resultFile>
Name of the file in which the comparison results will be stored (default: results). Missing .zip endings will be automatically added.
-t, --min-tokens=<minTokenMatch>
Tunes the comparison sensitivity by adjusting the minimum token required to be counted as a matching section. A smaller value increases the
sensitivity but might lead to more false-positives.

Advanced
--csv-export Export pairwise similarity values as a CSV file.
-d, --debug Store on-parsable files in error folder.
-d, --debug Store on-parsable files in error folder.
--log-level=<{ERROR, WARN, INFO, DEBUG, TRACE}>
Set the log level for the cli.
-m, --similarity-threshold=<similarityThreshold>
Comparison similarity threshold [0.0-1.0]: All
comparisons above this threshold will be saved
(default: 0.0).
-m, --similarity-threshold=<similarityThreshold>
Comparison similarity threshold [0.0-1.0]: All comparisons above this threshold will be saved (default: 0.0).
--overwrite Existing result files will be overwritten.
-p, --suffixes=<suffixes>[,<suffixes>...]
comma-separated list of all filename suffixes that are
included.
-P, --port=<port> The port used for the internal report viewer (default:
1996).
-s, --subdirectory=<subdirectory>
-p, --suffixes=<suffixes>[,<suffixes>...]
comma-separated list of all filename suffixes that are included.
-P, --port=<port> The port used for the internal report viewer (default: 1996).
-s, --subdirectory=<subdirectory>
Look in directories <root-dir>/*/<dir> for programs.
-x, --exclusion-file=<exclusionFileName>
All files named in this file will be ignored in the
comparison (line-separated list).
-x, --exclusion-file=<exclusionFileName>
All files named in this file will be ignored in the comparison (line-separated list).

Clustering
--cluster-alg, --cluster-algorithm=<{AGGLOMERATIVE, SPECTRAL}>
Specifies the clustering algorithm. Available
algorithms: agglomerative, spectral (default:
spectral).
Specifies the clustering algorithm. Available algorithms: agglomerative, spectral (default: spectral).
--cluster-metric=<{AVG, MIN, MAX, INTERSECTION}>
The similarity metric used for clustering. Available
metrics: average similarity, minimum similarity,
maximal similarity, matched tokens (default: average
similarity).
The similarity metric used for clustering. Available metrics: average similarity, minimum similarity, maximal similarity, matched tokens (default:
average similarity).
--cluster-skip Skips the cluster calculation.

Subsequence Match Merging
--gap-size=<maximumGapSize>
Maximal gap between neighboring matches to be merged
(between 1 and minTokenMatch, default: 6).
--match-merging Enables merging of neighboring matches to counteract
obfuscation attempts.
Maximal gap between neighboring matches to be merged (between 1 and minTokenMatch, default: 6).
--match-merging Enables merging of neighboring matches to counteract obfuscation attempts.
--neighbor-length=<minimumNeighborLength>
Minimal length of neighboring matches to be merged
(between 1 and minTokenMatch, default: 2).
Minimal length of neighboring matches to be merged (between 1 and minTokenMatch, default: 2).
Languages:
c
cpp
Expand All @@ -171,6 +144,7 @@ Languages:
javascript
kotlin
llvmir
multi
python3
rlang
rust
Expand Down
41 changes: 40 additions & 1 deletion cli/src/main/java/de/jplag/cli/CLI.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.slf4j.ILoggerFactory;
import org.slf4j.Logger;
Expand Down Expand Up @@ -32,6 +34,8 @@ public final class CLI {
private static final String OUTPUT_FILE_EXISTS = "The output file (also with suffixes e.g. results(1).zip) already exists. You can use --overwrite to overwrite the file.";
private static final String OUTPUT_FILE_NOT_WRITABLE = "The output file (%s) cannot be written to.";

private static final String ZIP_FILE_EXTENSION = ".zip";

private final CliInputHandler inputHandler;

/**
Expand All @@ -58,7 +62,8 @@ public void executeCli() throws ExitException, IOException {
switch (this.inputHandler.getCliOptions().mode) {
case RUN -> runJPlag();
case VIEW -> runViewer(this.inputHandler.getFileForViewMode());
case RUN_AND_VIEW -> runViewer(runJPlag());
case RUN_AND_VIEW -> runAndView();
case AUTO -> selectModeAutomatically();
}
}
}
Expand Down Expand Up @@ -105,6 +110,15 @@ public File runJPlag() throws ExitException, FileNotFoundException {
return target;
}

/**
* Runs JPlag and shows the result in the report viewer
* @throws IOException If something went wrong with the internal server
* @throws ExitException If JPlag threw an exception
*/
public void runAndView() throws IOException, ExitException {
runViewer(runJPlag());
}

/**
* Runs the report viewer using the given file as the default result.zip.
* @param zipFile The zip file to pass to the viewer. Can be null, if no result should be opened by default
Expand All @@ -115,6 +129,31 @@ public void runViewer(File zipFile) throws IOException {
JPlagRunner.runInternalServer(zipFile, this.inputHandler.getCliOptions().advanced.port);
}

private void selectModeAutomatically() throws IOException, ExitException {
TwoOfTwelve marked this conversation as resolved.
Show resolved Hide resolved
List<File> inputs = this.getAllInputs();

if (inputs.isEmpty()) {
this.runViewer(null);
return;
}

// if the selected mode is auto and there is exactly one zip file selected as an input it is opened in the report viewer
if (inputs.size() == 1 && inputs.getFirst().getName().endsWith(ZIP_FILE_EXTENSION)) {
this.runViewer(inputs.getFirst());
return;
}

this.runAndView();
}

private List<File> getAllInputs() {
List<File> inputs = new ArrayList<>();
inputs.addAll(List.of(this.inputHandler.getCliOptions().rootDirectory));
inputs.addAll(List.of(this.inputHandler.getCliOptions().newDirectories));
inputs.addAll(List.of(this.inputHandler.getCliOptions().oldDirectories));
return inputs;
}

private void finalizeLogger() {
ILoggerFactory factory = LoggerFactory.getILoggerFactory();
if (!(factory instanceof CollectedLoggerFactory collectedLoggerFactory)) {
Expand Down
2 changes: 1 addition & 1 deletion cli/src/main/java/de/jplag/cli/options/CliOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public class CliOptions implements Runnable {

@Option(names = {"-M",
"--mode"}, description = "The mode of JPlag. One of: ${COMPLETION-CANDIDATES} (default: ${DEFAULT_VALUE}). If VIEW is chosen, you can optionally specify a path to an existing report.")
public JPlagMode mode = JPlagMode.RUN_AND_VIEW;
public JPlagMode mode = JPlagMode.AUTO;

@Option(names = {"--normalize"}, description = "Activate the normalization of tokens. Supported for languages: Java, C++.")
public boolean normalize = false;
Expand Down
6 changes: 5 additions & 1 deletion cli/src/main/java/de/jplag/cli/options/JPlagMode.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,9 @@ public enum JPlagMode {
/**
* Run JPlag and open the result in report viewer
*/
RUN_AND_VIEW
RUN_AND_VIEW,
/**
* Choose the mode automatically from the given input files
*/
AUTO,
}
13 changes: 13 additions & 0 deletions cli/src/test/java/de/jplag/cli/ModeTest.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package de.jplag.cli;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrowsExactly;

import java.io.File;
Expand Down Expand Up @@ -53,6 +54,18 @@ void testViewWithMultipleFiles() {
});
}

@Test
void testImplicitView() throws IOException, ExitException {
CliInputHandler inputHandler = this.runCli(args -> args.with(CliArgument.RESULT_FILE, "result.zip")).inputHandler();
assertEquals(new File("result.zip"), inputHandler.getFileForViewMode());
}

@Test
void testImplicitReportViewer() throws IOException, ExitException {
CliInputHandler inputHandler = this.runCli().inputHandler();
assertNull(inputHandler.getFileForViewMode());
}

@Override
public void addDefaultParameters() {
// prevents the submission directory from being added to the parameters automatically
Expand Down
Loading
Loading