Skip to content

add stripping functionality #8

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

Merged
merged 1 commit into from
Jun 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ To use the plugin, insert the following configuration into the plugins section o
<plugin>
<groupId>org.atp-fivt</groupId>
<artifactId>export-maven-plugin</artifactId>
<version>1.1</version>
<version>1.2</version>
<configuration>
<zipFileName>Name_Surname.zip</zipFileName>
</configuration>
Expand Down
60 changes: 46 additions & 14 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>org.atp-fivt</groupId>
<artifactId>export-maven-plugin</artifactId>
<version>1.1</version>
<version>1.2</version>
<packaging>maven-plugin</packaging>

<name>Maven project export plugin</name>
Expand Down Expand Up @@ -48,13 +48,6 @@
<checkstyle.version>10.25.0</checkstyle.version>
</properties>

<distributionManagement>
<repository>
<id>ossrh</id>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
</distributionManagement>

<dependencies>
<dependency>
<groupId>org.eclipse.jgit</groupId>
Expand Down Expand Up @@ -156,6 +149,45 @@
</executions>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.3.1</version>
<executions>
<execution>
<id>attach-sources</id>
<!-- run before the GPG “verify” phase so the JAR gets signed -->
<phase>prepare-package</phase>
<goals>
<!-- jar-no-fork = no extra compile cycle -->
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.6.3</version>
<configuration>
<!-- silence doclint warnings that break the build on JDK 8+ -->
<source>${maven.compiler.target}</source>
<doclint>none</doclint>
<failOnError>false</failOnError>
</configuration>
<executions>
<execution>
<id>attach-javadoc</id>
<phase>prepare-package</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>


<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
Expand All @@ -171,14 +203,14 @@
</executions>
</plugin>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.7.0</version>
<groupId>org.sonatype.central</groupId>
<artifactId>central-publishing-maven-plugin</artifactId>
<version>0.7.0</version>
<extensions>true</extensions>
<configuration>
<serverId>ossrh</serverId>
<nexusUrl>https://oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>true</autoReleaseAfterClose>
<publishingServerId>central</publishingServerId>
<autoPublish>true</autoPublish>
<waitUntil>validated</waitUntil>
</configuration>
</plugin>
</plugins>
Expand Down
32 changes: 31 additions & 1 deletion src/main/java/org/atpfivt/ExportMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,16 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import static org.atpfivt.StripMarkedSections.stripMarkedSections;

/**
* Goal which exports the project into zip file respecting .gitignore.
*/
Expand All @@ -33,6 +36,9 @@ public final class ExportMojo extends AbstractMojo {
@Parameter(defaultValue = "export.zip")
private String zipFileName;

@Parameter(defaultValue = "false")
private boolean stripMarked;

void setBaseDirectory(File baseDirectory) {
this.baseDirectory = baseDirectory;
}
Expand All @@ -45,10 +51,15 @@ void setZipFileName(String zipFileName) {
this.zipFileName = zipFileName;
}

void setStripMarked(boolean stripMarked) {
this.stripMarked = stripMarked;
}

private boolean isNotInBuildDirectory(Path path) {
return !path.startsWith(buildDirectory.toPath());
}


public void execute()
throws MojoExecutionException {
Path buildPath = buildDirectory.toPath();
Expand All @@ -65,7 +76,26 @@ public void execute()
for (Path path : pathList) {
URI relativePath = basePath.toUri().relativize(path.toUri());
zos.putNextEntry(new ZipEntry(relativePath.toString()));
Files.copy(path, zos);
String fileName = path.getFileName().toString();
if (stripMarked && fileName.endsWith(".java")) {
/* ----- JAVA SOURCE: strip //[[ … //]] blocks ----- */
String src = Files.readString(path, StandardCharsets.UTF_8);
String cleaned = stripMarkedSections(src);
if (cleaned.length() != src.length()) {
getLog().info("Stripped file: " + path);
}
zos.write(cleaned.getBytes(StandardCharsets.UTF_8));

} else if (stripMarked && "pom.xml".equals(fileName)) {
/* ----- POM: remove the export-plugin marker ----- */
String pom = Files.readString(path, StandardCharsets.UTF_8);
String cleaned = pom.replace("<stripMarked>true</stripMarked>", "");
zos.write(cleaned.getBytes(StandardCharsets.UTF_8));

} else {
/* ----- Everything else copied verbatim ----- */
Files.copy(path, zos);
}
zos.closeEntry();
}
}
Expand Down
27 changes: 27 additions & 0 deletions src/main/java/org/atpfivt/StripMarkedSections.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.atpfivt;

final class StripMarkedSections {
private StripMarkedSections() {

}
static String stripMarkedSections(String src) {
StringBuilder out = new StringBuilder(src.length());
int cursor = 0;

while (cursor < src.length()) {
int open = src.indexOf("//[[", cursor);
if (open == -1) { // no more markers
out.append(src, cursor, src.length());
break;
}
out.append(src, cursor, open); // keep text before "[["
int close = src.indexOf("//]]", open + 4);
if (close == -1) { // unmatched start → keep the rest
out.append(src, open, src.length());
break;
}
cursor = close + 4; // jump past "]]" and continue
}
return out.toString();
}
}
85 changes: 80 additions & 5 deletions src/test/java/org/atpfivt/ExportMojoTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,18 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.*;

class ExportMojoTest {
private ExportMojo exportMojo;
Expand Down Expand Up @@ -50,6 +49,10 @@ void exportSavesFilesRespectingTheGitignore() throws MojoExecutionException, IOE
ZipEntry nextEntry;
while ((nextEntry = zipInputStream.getNextEntry()) != null) {
filenames.add(nextEntry.getName());
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
zipInputStream.transferTo(baos);
assertTrue(baos.toString(StandardCharsets.UTF_8).contains("test"));
}
}
}
assertEquals(Set.of("a", "b", ".gitignore", "src/foo"), filenames);
Expand All @@ -67,11 +70,83 @@ void exportOmitsTargetEvenIfNoGitignoreProvided() throws MojoExecutionException,
ZipEntry nextEntry;
while ((nextEntry = zipInputStream.getNextEntry()) != null) {
filenames.add(nextEntry.getName());
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
zipInputStream.transferTo(baos);
assertEquals("test", baos.toString(StandardCharsets.UTF_8));
}
}
}
assertEquals(Set.of("a", "b", "a.ignoreme"), filenames);
}


@Test
void exportStripsMarkedSectionsAndPomTag() throws MojoExecutionException, IOException {
/* ── Arrange: project structure ─────────────────────────────────────────── */
// Java source with two marked regions
String javaSrc =
"public class StudentExercise {\n" +
" //[[\n" +
" private int answer = 42;\n" +
" //]]\n" +
" public void solve() {\n" +
" //[[\n" +
" System.out.println(answer);\n" +
" //]]\n" +
" }\n" +
"}\n";
Files.writeString(root.resolve("StudentExercise.java"), javaSrc, StandardCharsets.UTF_8);

// POM with the marker flag
String pom =
"<project>\n" +
" <modelVersion>4.0.0</modelVersion>\n" +
" <groupId>example</groupId>\n" +
" <artifactId>exercise</artifactId>\n" +
" <version>1.0-SNAPSHOT</version>\n" +
" <properties>\n" +
" <stripMarked>true</stripMarked>\n" +
" </properties>\n" +
"</project>\n";
Files.writeString(root.resolve("pom.xml"), pom, StandardCharsets.UTF_8);

// Enable strip-marked mode
exportMojo.setStripMarked(true);

/* ── Act: run the mojo ──────────────────────────────────────────────────── */
exportMojo.execute();

/* ── Assert: check the produced ZIP ─────────────────────────────────────── */
Map<String, String> zipContents = new HashMap<>();
try (ZipInputStream zis = new ZipInputStream(
new FileInputStream(target.resolve("export.zip").toFile()),
StandardCharsets.UTF_8)) {

ZipEntry entry;
while ((entry = zis.getNextEntry()) != null) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
zis.transferTo(baos);
zipContents.put(entry.getName(), baos.toString(StandardCharsets.UTF_8));
}
}

// 1. ZIP contains the expected files
assertEquals(Set.of("StudentExercise.java", "pom.xml"), zipContents.keySet());

// 2. Java source has no \\[[ or \\]] and the secret implementation vanished
String strippedJava = zipContents.get("StudentExercise.java");
assertFalse(strippedJava.contains("//[["), "Markers must be removed");
assertFalse(strippedJava.contains("//]]"), "Markers must be removed");
assertFalse(strippedJava.contains("answer = 42"), "Hidden code must be removed");
assertFalse(strippedJava.contains("println"), "Second hidden block must be removed");

// 3. pom.xml no longer contains the marker element
String strippedPom = zipContents.get("pom.xml");
assertFalse(strippedPom.contains("<stripMarked>true</stripMarked>"),
"pom.xml should not expose the stripMarked flag to students");
}


@AfterEach
void tearDown() throws IOException {
Files.walk(root)
Expand Down
35 changes: 35 additions & 0 deletions src/test/java/org/atpfivt/StripMarkedSectionsTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.atpfivt;

import org.junit.jupiter.api.Test;

import static org.atpfivt.StripMarkedSections.stripMarkedSections;
import static org.junit.jupiter.api.Assertions.*;

class StripMarkedSectionsTest {

@Test
void noMarkers() {
String src = "public class Foo { }";
assertEquals(src, stripMarkedSections(src));
}

@Test
void oneMarker() {
String src = "before //[[hidden//]] after";
String expected = "before after";
assertEquals(expected, stripMarkedSections(src));
}

@Test
void multipleMarkers() {
String src = "a //[[x//]] b //[[y//]] c";
String expected = "a b c";
assertEquals(expected, stripMarkedSections(src));
}

@Test
void unmatchedStart() {
String src = "keep //[[oops";
assertEquals(src, stripMarkedSections(src));
}
}