From 014e121fd83315e6259c28cf3fd2497e090c2bac Mon Sep 17 00:00:00 2001 From: Phillip Kruger Date: Wed, 17 Apr 2024 12:26:32 +1000 Subject: [PATCH] New Content view for jar files Signed-off-by: Phillip Kruger --- .locker/pom.xml | 2 +- README.md | 2 +- pom.xml | 2 +- src/main/java/io/mvnpm/JarAsset.java | 43 + src/main/java/io/mvnpm/JarContentsApi.java | 199 +++ src/main/java/io/mvnpm/JarLibrary.java | 45 + src/main/resources/web/app/mvnpm-doc.ts | 5 +- src/main/resources/web/app/mvnpm-home.ts | 10 +- src/main/resources/web/app/mvnpm-jar-view.ts | 86 + src/main/resources/web/app/mvnpm-live.ts | 12 - src/main/resources/web/app/mvnpm-releases.ts | 5 - src/main/resources/web/app/mvnpm.css | 2 +- .../web/static/how-does-mvnpm-work.excalidraw | 1501 +++++++++++++++++ .../web/static/how-does-mvnpm-work.png | Bin 0 -> 138510 bytes src/main/resources/web/static/mvnpm.png | Bin 69135 -> 0 bytes 15 files changed, 1884 insertions(+), 30 deletions(-) create mode 100644 src/main/java/io/mvnpm/JarAsset.java create mode 100644 src/main/java/io/mvnpm/JarContentsApi.java create mode 100644 src/main/java/io/mvnpm/JarLibrary.java create mode 100644 src/main/resources/web/app/mvnpm-jar-view.ts create mode 100644 src/main/resources/web/static/how-does-mvnpm-work.excalidraw create mode 100644 src/main/resources/web/static/how-does-mvnpm-work.png delete mode 100644 src/main/resources/web/static/mvnpm.png diff --git a/.locker/pom.xml b/.locker/pom.xml index 6bdb3c2..e72a6e0 100644 --- a/.locker/pom.xml +++ b/.locker/pom.xml @@ -5,7 +5,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 4.0.0 io.mvnpm - 3.0.33-SNAPSHOT + 3.0.34-SNAPSHOT mvnpm-locker pom diff --git a/README.md b/README.md index 6918511..df3ad7c 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ to use it in your local Maven settings add the following to your settings.xml (t ### How does the mvnpm Maven repository work ? -![Schema](src/main/resources/web/static/mvnpm.png) +![Schema](src/main/resources/web/static/how-does-mvnpm-work.png) * Developer's Maven build requests an npm package from Maven Central. * Maven Central returns a 404 if the package does not exist. diff --git a/pom.xml b/pom.xml index ac9e1ff..9380342 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 io.mvnpm mvnpm - 3.0.33-SNAPSHOT + 3.0.34-SNAPSHOT mvnpm Maven on NPM https://mvnpm.org/ diff --git a/src/main/java/io/mvnpm/JarAsset.java b/src/main/java/io/mvnpm/JarAsset.java new file mode 100644 index 0000000..1066f7c --- /dev/null +++ b/src/main/java/io/mvnpm/JarAsset.java @@ -0,0 +1,43 @@ +package io.mvnpm; + +import java.util.List; + +public class JarAsset { + private String name; + private List children; + private boolean fileAsset; + private String urlPart; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getChildren() { + return children; + } + + public void setChildren(List children) { + this.children = children; + } + + public boolean isFileAsset() { + return fileAsset; + } + + public void setFileAsset(boolean fileAsset) { + this.fileAsset = fileAsset; + } + + public String getUrlPart() { + return urlPart; + } + + public void setUrlPart(String urlPart) { + this.urlPart = urlPart; + } + +} diff --git a/src/main/java/io/mvnpm/JarContentsApi.java b/src/main/java/io/mvnpm/JarContentsApi.java new file mode 100644 index 0000000..5d514ac --- /dev/null +++ b/src/main/java/io/mvnpm/JarContentsApi.java @@ -0,0 +1,199 @@ +package io.mvnpm; + +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.jar.JarFile; + +import jakarta.inject.Inject; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; + +import org.apache.commons.compress.archivers.ArchiveEntry; +import org.apache.commons.compress.archivers.tar.TarArchiveEntry; +import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; +import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; + +import io.mvnpm.file.FileType; +import io.mvnpm.maven.MavenRepositoryService; +import io.mvnpm.maven.NameVersionType; +import io.mvnpm.maven.UrlPathParser; + +/** + * Get the file listing for a jar file + * + * @author Phillip Kruger (phillip.kruger@gmail.com) + */ +@Path("/api") +public class JarContentsApi { + + @Inject + MavenRepositoryService mavenRepositoryService; + + @GET + @Path("/org/mvnpm/{gavt : (.+)?}.jar") + public JarLibrary getJar(@PathParam("gavt") String gavt) { + NameVersionType nameVersionType = UrlPathParser.parseMavenFile(gavt); + return loadJarLibrary(nameVersionType, FileType.jar); + } + + @GET + @Path("/org/mvnpm/{gavt : (.+)?}-sources.jar") + public JarLibrary getSourcesJar(@PathParam("gavt") String gavt) { + NameVersionType nameVersionType = UrlPathParser.parseMavenFile(gavt); + return loadJarLibrary(nameVersionType, FileType.source); + } + + @GET + @Path("/org/mvnpm/{gavt : (.+)?}-javadoc.jar") + public JarLibrary getJavadocJar(@PathParam("gavt") String gavt) { + NameVersionType nameVersionType = UrlPathParser.parseMavenFile(gavt); + return loadJarLibrary(nameVersionType, FileType.javadoc); + } + + @GET + @Path("/org/mvnpm/{gavt : (.+)?}.tgz") + public JarLibrary getTgz(@PathParam("gavt") String gavt) { + NameVersionType nameVersionType = UrlPathParser.parseMavenFile(gavt); + return loadTarGzLibrary(nameVersionType); + } + + private JarLibrary loadJarLibrary(NameVersionType nameVersionType, FileType filetype) { + java.nio.file.Path path = mavenRepositoryService.getPath(nameVersionType.name(), nameVersionType.version(), + filetype); + + JarLibrary library = new JarLibrary(nameVersionType.name().displayName); + library.setVersion(nameVersionType.version()); + library.setType(filetype.getPostString()); + + try (JarFile jarFile = new JarFile(path.toString())) { + Map assetMap = new HashMap<>(); + + // Create a root asset + JarAsset rootAsset = new JarAsset(); + rootAsset.setName("/"); + rootAsset.setFileAsset(false); + rootAsset.setChildren(new ArrayList<>()); + assetMap.put("/", rootAsset); + + // Iterate through the entries of the jar file + jarFile.stream().forEach(entry -> { + String name = entry.getName(); + boolean isFile = !entry.isDirectory(); + String[] parts = name.split("/"); + StringBuilder pathBuilder = new StringBuilder("/"); + + JarAsset currentParent = rootAsset; + + // Process each part of the entry's name + for (int i = 0; i < parts.length - (isFile ? 1 : 0); i++) { + pathBuilder.append(parts[i]); + String currentPath = pathBuilder.toString() + "/"; + + if (!assetMap.containsKey(currentPath)) { + JarAsset newAsset = new JarAsset(); + newAsset.setName(parts[i]); + newAsset.setFileAsset(false); + newAsset.setUrlPart(currentPath); + newAsset.setChildren(new ArrayList<>()); + + currentParent.getChildren().add(newAsset); + assetMap.put(currentPath, newAsset); + } + + currentParent = assetMap.get(currentPath); + pathBuilder.append("/"); + } + + // If it's a file, add it to the current parent directory + if (isFile) { + JarAsset fileAsset = new JarAsset(); + fileAsset.setName(parts[parts.length - 1]); + fileAsset.setFileAsset(true); + fileAsset.setUrlPart(name); + currentParent.getChildren().add(fileAsset); + } + }); + + library.setRootAsset(rootAsset); + + } catch (IOException e) { + e.printStackTrace(); + } + + return library; + } + + private JarLibrary loadTarGzLibrary(NameVersionType nameVersionType) { + java.nio.file.Path path = mavenRepositoryService.getPath(nameVersionType.name(), nameVersionType.version(), + FileType.tgz); + + JarLibrary library = new JarLibrary(nameVersionType.name().displayName); + library.setVersion(nameVersionType.version()); + library.setType(FileType.tgz.getPostString()); + + Map assetMap = new HashMap<>(); + JarAsset rootAsset = new JarAsset(); + rootAsset.setName("/"); + rootAsset.setFileAsset(false); + rootAsset.setChildren(new ArrayList<>()); + assetMap.put("/", rootAsset); + + try (FileInputStream fin = new FileInputStream(path.toFile()); + GzipCompressorInputStream gzIn = new GzipCompressorInputStream(fin); + TarArchiveInputStream tarIn = new TarArchiveInputStream(gzIn)) { + + ArchiveEntry entry; + + while ((entry = tarIn.getNextEntry()) != null) { + if (!tarIn.canReadEntryData(entry)) { + continue; + } + String name = entry.getName(); + boolean isFile = !((TarArchiveEntry) entry).isDirectory(); + String[] parts = name.split("/"); + StringBuilder pathBuilder = new StringBuilder("/"); + + JarAsset currentParent = rootAsset; + + // Process each part of the entry's name + for (int i = 0; i < parts.length - (isFile ? 1 : 0); i++) { + pathBuilder.append(parts[i]); + String currentPath = pathBuilder.toString() + "/"; + + if (!assetMap.containsKey(currentPath)) { + JarAsset newAsset = new JarAsset(); + newAsset.setName(parts[i]); + newAsset.setFileAsset(false); + newAsset.setUrlPart(currentPath); + newAsset.setChildren(new ArrayList<>()); + + currentParent.getChildren().add(newAsset); + assetMap.put(currentPath, newAsset); + } + + currentParent = assetMap.get(currentPath); + pathBuilder.append("/"); + } + + // If it's a file, add it to the current parent directory + if (isFile) { + JarAsset fileAsset = new JarAsset(); + fileAsset.setName(parts[parts.length - 1]); + fileAsset.setFileAsset(true); + fileAsset.setUrlPart(name); + currentParent.getChildren().add(fileAsset); + } + } + library.setRootAsset(rootAsset); + } catch (IOException e) { + e.printStackTrace(); + } + + return library; + } + +} diff --git a/src/main/java/io/mvnpm/JarLibrary.java b/src/main/java/io/mvnpm/JarLibrary.java new file mode 100644 index 0000000..9313175 --- /dev/null +++ b/src/main/java/io/mvnpm/JarLibrary.java @@ -0,0 +1,45 @@ +package io.mvnpm; + +/** + * Represent the contents of a Jar Library + * + * @author Phillip Kruger (phillip.kruger@gmail.com) + */ +public class JarLibrary { + private final String jarName; + private String version; + private String type; + private JarAsset rootAsset; + + public JarLibrary(String jarName) { + this.jarName = jarName; + } + + public String getJarName() { + return jarName; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public JarAsset getRootAsset() { + return rootAsset; + } + + public void setRootAsset(JarAsset rootAsset) { + this.rootAsset = rootAsset; + } +} diff --git a/src/main/resources/web/app/mvnpm-doc.ts b/src/main/resources/web/app/mvnpm-doc.ts index a4693e0..35ca304 100644 --- a/src/main/resources/web/app/mvnpm-doc.ts +++ b/src/main/resources/web/app/mvnpm-doc.ts @@ -47,6 +47,9 @@ export class MvnpmDoc extends LitElement { text-decoration: none; color:var(--lumo-body-text-color); } + .how{ + width: 100%; + } `; @state() _dep: string = ` @@ -156,7 +159,7 @@ export class MvnpmDoc extends LitElement {

How does the mvnpm Maven repository work ?

- +