Skip to content

Commit

Permalink
Merge pull request #1576 from jplag/develop
Browse files Browse the repository at this point in the history
Merge develop into main for the upcoming 5.0.0 major release
  • Loading branch information
tsaglam authored Feb 21, 2024
2 parents 065e79e + 5d1ce9d commit dc1d2df
Show file tree
Hide file tree
Showing 239 changed files with 3,909 additions and 1,934 deletions.
Binary file modified .github/workflows/files/progpedia.zip
Binary file not shown.
18 changes: 11 additions & 7 deletions .github/workflows/maven.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: Build

on:
push:
push:
paths:
- ".github/workflows/maven.yml"
- "**/pom.xml"
Expand All @@ -14,7 +14,7 @@ on:
- "**/pom.xml"
- "**.java"
- "**.g4"

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:

Expand Down Expand Up @@ -43,17 +43,21 @@ jobs:
with:
java-version: 21
distribution: 'temurin'


- uses: actions/setup-node@v4
with:
node-version: "18"

- name: Run Tests
run: mvn verify -B -U

- name: Build Assembly
run: mvn clean package assembly:single
run: mvn -Pwith-report-viewer clean package assembly:single

- name: Upload Assembly
uses: actions/upload-artifact@v4
with:
name: "JPlag"
path: "jplag.cli/target/jplag-*-jar-with-dependencies.jar"


8 changes: 6 additions & 2 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
java-version: '21'
distribution: 'temurin'
- name: Set maven settings.xml
uses: whelk-io/maven-settings-xml-action@v21
uses: whelk-io/maven-settings-xml-action@v22
with:
servers: '[{ "id": "ossrh", "username": "jplag", "password": "${{ secrets.OSSRH_TOKEN }}" }]'
- name: Import GPG key
Expand All @@ -34,8 +34,12 @@ jobs:
with:
java-version: '21'
distribution: 'temurin'
- uses: actions/setup-node@v4
with:
node-version: "18"

- name: Build JPlag
run: mvn -U -B clean package assembly:single
run: mvn -Pwith-report-viewer -U -B clean package assembly:single

- name: Attach CLI to Release on GitHub
uses: softprops/action-gh-release@v1
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/sonarcloud-branch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2

- name: Build and analyze
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/sonarcloud-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ jobs:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2

- name: Build and analyze (PR)
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/spotless.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ on:
- "**/pom.xml"
- "**.java"
- "**.g4"

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:

Expand Down Expand Up @@ -43,9 +43,9 @@ jobs:
with:
java-version: 21
distribution: 'temurin'

- name: Check with Spotless
run: mvn clean spotless:check



162 changes: 74 additions & 88 deletions README.md

Large diffs are not rendered by default.

63 changes: 61 additions & 2 deletions cli/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<version>${revision}</version>
</parent>
<artifactId>cli</artifactId>

<dependencies>
<!-- IMPORTANT: For Coverage testing, you have to add dependencies to the coverage-report project ! -->

Expand Down Expand Up @@ -44,12 +45,12 @@
</dependency>
<dependency>
<groupId>de.jplag</groupId>
<artifactId>cpp</artifactId>
<artifactId>c</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>de.jplag</groupId>
<artifactId>cpp2</artifactId>
<artifactId>cpp</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
Expand Down Expand Up @@ -128,6 +129,12 @@
<artifactId>picocli</artifactId>
<version>4.7.5</version>
</dependency>

<dependency>
<groupId>me.tongfei</groupId>
<artifactId>progressbar</artifactId>
<version>0.10.0</version>
</dependency>
</dependencies>
<build>
<plugins>
Expand Down Expand Up @@ -161,4 +168,56 @@
</plugin>
</plugins>
</build>

<profiles>
<profile>
<id>with-report-viewer</id>
<build>
<resources>
<resource>
<targetPath>report-viewer</targetPath>
<directory>../report-viewer/dist</directory>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.3.2</version>
<executions>
<execution>
<id>npm install</id>
<goals>
<goal>exec</goal>
</goals>
<phase>generate-resources</phase>
<configuration>
<executable>npm</executable>
<workingDirectory>../report-viewer</workingDirectory>
<arguments>
<argument>install</argument>
</arguments>
</configuration>
</execution>
<execution>
<id>npm build</id>
<goals>
<goal>exec</goal>
</goals>
<phase>generate-resources</phase>
<configuration>
<executable>npm</executable>
<workingDirectory>../report-viewer</workingDirectory>
<arguments>
<argument>run</argument>
<argument>build</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
107 changes: 75 additions & 32 deletions cli/src/main/java/de/jplag/cli/CLI.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@
import static picocli.CommandLine.Model.UsageMessageSpec.SECTION_KEY_OPTION_LIST;
import static picocli.CommandLine.Model.UsageMessageSpec.SECTION_KEY_SYNOPSIS;

import java.awt.Desktop;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URI;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.HashSet;
Expand All @@ -21,9 +25,12 @@
import de.jplag.JPlagResult;
import de.jplag.Language;
import de.jplag.cli.logger.CollectedLoggerFactory;
import de.jplag.cli.logger.TongfeiProgressBarProvider;
import de.jplag.cli.server.ReportViewer;
import de.jplag.clustering.ClusteringOptions;
import de.jplag.clustering.Preprocessing;
import de.jplag.exceptions.ExitException;
import de.jplag.logging.ProgressBarLogger;
import de.jplag.merging.MergingOptions;
import de.jplag.options.JPlagOptions;
import de.jplag.options.LanguageOption;
Expand All @@ -45,12 +52,12 @@ public final class CLI {

private static final Random RANDOM = new SecureRandom();

private static final String CREDITS = "Created by IPD Tichy, Guido Malpohl, and others. JPlag logo designed by Sandro Koch. Currently maintained by Sebastian Hahner and Timur Saglam.";
private static final String CREDITS = "Created by IPD Tichy, Guido Malpohl, and others. Maintained by Timur Saglam and Sebastian Hahner. Logo by Sandro Koch.";

private static final String[] DESCRIPTIONS = {"Detecting Software Plagiarism", "Software-Archaeological Playground", "Since 1996",
"Scientifically Published", "Maintained by SDQ", "RIP Structure and Table", "What else?", "You have been warned!", "Since Java 1.0",
"More Abstract than Tree", "Students Nightmare", "No, changing variable names does not work", "The tech is out there!",
"Developed by plagiarism experts."};
"More Abstract than Tree", "Students Nightmare", "No, changing variable names does not work...", "The tech is out there!",
"Developed by plagiarism experts.", "State of the Art Obfuscation Resilience", "www.helmholtz.software/software/jplag"};

private static final String OPTION_LIST_HEADING = "Parameter descriptions: ";

Expand All @@ -63,6 +70,8 @@ public final class CLI {

private static final String DESCRIPTION_PATTERN = "%nJPlag - %s%n%s%n%n";

private static final String DEFAULT_FILE_ENDING = ".zip";

/**
* Main class for using JPlag via the CLI.
* @param args are the CLI arguments that will be passed to JPlag.
Expand All @@ -76,15 +85,20 @@ public static void main(String[] args) {
ParseResult parseResult = cli.parseOptions(args);

if (!parseResult.isUsageHelpRequested() && !(parseResult.subcommand() != null && parseResult.subcommand().isUsageHelpRequested())) {
JPlagOptions options = cli.buildOptionsFromArguments(parseResult);
JPlagResult result = JPlag.run(options);
ReportObjectFactory reportObjectFactory = new ReportObjectFactory();
reportObjectFactory.createAndSaveReport(result, cli.getResultFolder());

OutputFileGenerator.generateCsvOutput(result, new File(cli.getResultFolder()), cli.options);
ProgressBarLogger.setProgressBarProvider(new TongfeiProgressBarProvider());
switch (cli.options.mode) {
case RUN -> cli.runJPlag(parseResult);
case VIEW -> cli.runViewer(null);
case RUN_AND_VIEW -> cli.runViewer(cli.runJPlag(parseResult));
}
}
} catch (ExitException | IOException exception) { // do not pass exceptions here to keep log clean
if (exception.getCause() != null) {
logger.error("{} - {}", exception.getMessage(), exception.getCause().getMessage());
} else {
logger.error(exception.getMessage());
}
} catch (ExitException exception) {
logger.error(exception.getMessage()); // do not pass exception here to keep log clean

finalizeLogger();
System.exit(1);
}
Expand All @@ -102,9 +116,8 @@ public CLI() {
this.commandLine.getHelpSectionMap().put(SECTION_KEY_OPTION_LIST, help -> help.optionList().lines().map(it -> {
if (it.startsWith(" -")) {
return " " + it;
} else {
return it;
}
return it;
}).collect(Collectors.joining(System.lineSeparator())));

buildSubcommands().forEach(commandLine::addSubcommand);
Expand All @@ -114,6 +127,29 @@ public CLI() {
this.commandLine.setAllowSubcommandsAsOptionParameters(true);
}

public File runJPlag(ParseResult parseResult) throws ExitException, FileNotFoundException {
JPlagOptions jplagOptions = buildOptionsFromArguments(parseResult);
JPlagResult result = JPlag.run(jplagOptions);
File target = new File(getResultFilePath());
ReportObjectFactory reportObjectFactory = new ReportObjectFactory(target);
reportObjectFactory.createAndSaveReport(result);
logger.info("Successfully written the result: {}", target.getPath());
logger.info("View the result using --mode or at: https://jplag.github.io/JPlag/");
OutputFileGenerator.generateCsvOutput(result, new File(getResultFileBaseName()), this.options);
return target;
}

public void runViewer(File zipFile) throws IOException {
ReportViewer reportViewer = new ReportViewer(zipFile, this.options.advanced.port);
int port = reportViewer.start();
logger.info("ReportViewer started on port http://localhost:{}", port);
Desktop.getDesktop().browse(URI.create("http://localhost:" + port + "/"));

System.out.println("Press Enter key to exit...");
System.in.read();
reportViewer.stop();
}

private List<CommandSpec> buildSubcommands() {
return LanguageLoader.getAllAvailableLanguages().values().stream().map(language -> {
CommandSpec command = CommandSpec.create().name(language.getIdentifier());
Expand Down Expand Up @@ -143,7 +179,7 @@ public ParseResult parseOptions(String... args) throws CliException {
}
return result;
} catch (CommandLine.ParameterException e) {
if (e.getArgSpec().isOption() && Arrays.asList(((OptionSpec) e.getArgSpec()).names()).contains("-l")) {
if (e.getArgSpec() != null && e.getArgSpec().isOption() && Arrays.asList(((OptionSpec) e.getArgSpec()).names()).contains("-l")) {
throw new CliException(String.format(UNKOWN_LANGAUGE_EXCEPTION, e.getValue(),
String.join(", ", LanguageLoader.getAllAvailableLanguageIdentifiers())));
}
Expand Down Expand Up @@ -181,33 +217,31 @@ public JPlagOptions buildOptionsFromArguments(ParseResult parseResult) throws Cl
JPlagOptions jPlagOptions = new JPlagOptions(loadLanguage(parseResult), this.options.minTokenMatch, submissionDirectories,
oldSubmissionDirectories, null, this.options.advanced.subdirectory, suffixes, this.options.advanced.exclusionFileName,
JPlagOptions.DEFAULT_SIMILARITY_METRIC, this.options.advanced.similarityThreshold, this.options.shownComparisons, clusteringOptions,
this.options.advanced.debug, mergingOptions);
this.options.advanced.debug, mergingOptions, this.options.normalize);

String baseCodePath = this.options.baseCode;
File baseCodeDirectory = baseCodePath == null ? null : new File(baseCodePath);
if (baseCodeDirectory == null || baseCodeDirectory.exists()) {
return jPlagOptions.withBaseCodeSubmissionDirectory(baseCodeDirectory);
} else {
logger.warn("Using legacy partial base code API. Please migrate to new full path base code API.");
return jPlagOptions.withBaseCodeSubmissionName(baseCodePath);
}
logger.warn("Using legacy partial base code API. Please migrate to new full path base code API.");
return jPlagOptions.withBaseCodeSubmissionName(baseCodePath);
}

private Language loadLanguage(ParseResult result) throws CliException {
if (result.subcommand() != null) {
ParseResult subcommandResult = result.subcommand();
Language language = LanguageLoader.getLanguage(subcommandResult.commandSpec().name())
.orElseThrow(() -> new CliException(IMPOSSIBLE_EXCEPTION));
LanguageOptions languageOptions = language.getOptions();
languageOptions.getOptionsAsList().forEach(option -> {
if (subcommandResult.hasMatchedOption(option.getNameAsUnixParameter())) {
option.setValue(subcommandResult.matchedOptionValue(option.getNameAsUnixParameter(), null));
}
});
return language;
} else {
if (result.subcommand() == null) {
return this.options.language;
}
ParseResult subcommandResult = result.subcommand();
Language language = LanguageLoader.getLanguage(subcommandResult.commandSpec().name())
.orElseThrow(() -> new CliException(IMPOSSIBLE_EXCEPTION));
LanguageOptions languageOptions = language.getOptions();
languageOptions.getOptionsAsList().forEach(option -> {
if (subcommandResult.hasMatchedOption(option.getNameAsUnixParameter())) {
option.setValue(subcommandResult.matchedOptionValue(option.getNameAsUnixParameter(), null));
}
});
return language;
}

private static ClusteringOptions getClusteringOptions(CliOptions options) {
Expand Down Expand Up @@ -249,7 +283,16 @@ private String generateDescription() {
return String.format(DESCRIPTION_PATTERN, randomDescription, CREDITS);
}

public String getResultFolder() {
return this.options.resultFolder;
private String getResultFilePath() {
String optionValue = this.options.resultFile;
if (optionValue.endsWith(DEFAULT_FILE_ENDING)) {
return optionValue;
}
return optionValue + DEFAULT_FILE_ENDING;
}

private String getResultFileBaseName() {
String defaultOutputFile = getResultFilePath();
return defaultOutputFile.substring(0, defaultOutputFile.length() - DEFAULT_FILE_ENDING.length());
}
}
Loading

0 comments on commit dc1d2df

Please sign in to comment.