From 78d54afcdb4bcb204cc423ff7033b97fff1b9c1d Mon Sep 17 00:00:00 2001 From: Thomas Rubini <74205383+ThomasRubini@users.noreply.github.com> Date: Mon, 12 Dec 2022 16:43:06 +0100 Subject: [PATCH 1/6] add getters and setters to Package and SearchedPackage --- .../fr/packageviewer/ArchParser/Package.java | 6 ++++- .../ArchParser/SearchedPackage.java | 26 ++++++++++++++++--- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/main/java/fr/packageviewer/ArchParser/Package.java b/src/main/java/fr/packageviewer/ArchParser/Package.java index 321555e..59470da 100644 --- a/src/main/java/fr/packageviewer/ArchParser/Package.java +++ b/src/main/java/fr/packageviewer/ArchParser/Package.java @@ -3,7 +3,11 @@ package fr.packageviewer.ArchParser; import java.util.List; public class Package extends SearchedPackage { - List deps; + private final List deps; + + public List getDeps() { + return deps; + } public Package(String name, String version, String repo, String description, List deps) { super(name, version, repo, description); diff --git a/src/main/java/fr/packageviewer/ArchParser/SearchedPackage.java b/src/main/java/fr/packageviewer/ArchParser/SearchedPackage.java index 205756d..a761e9f 100644 --- a/src/main/java/fr/packageviewer/ArchParser/SearchedPackage.java +++ b/src/main/java/fr/packageviewer/ArchParser/SearchedPackage.java @@ -1,10 +1,26 @@ package fr.packageviewer.ArchParser; public class SearchedPackage { - String name; - String version; - String repo; - String description; + private final String name; + private final String version; + private final String repo; + private final String description; + + public String getName() { + return name; + } + + public String getVersion() { + return version; + } + + public String getRepo() { + return repo; + } + + public String getDescription() { + return description; + } public SearchedPackage(String name, String version, String repo, String desciption) { this.name = name; @@ -13,4 +29,6 @@ public class SearchedPackage { this.description = desciption; } + + } From c137515eb821e8f77cab8e71f3f3bb55dea684a7 Mon Sep 17 00:00:00 2001 From: Thomas Rubini <74205383+ThomasRubini@users.noreply.github.com> Date: Mon, 12 Dec 2022 16:46:10 +0100 Subject: [PATCH 2/6] add .toString() to Package and SearchedPackage --- src/main/java/fr/packageviewer/ArchParser/Package.java | 4 ++++ .../java/fr/packageviewer/ArchParser/SearchedPackage.java | 6 ++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/java/fr/packageviewer/ArchParser/Package.java b/src/main/java/fr/packageviewer/ArchParser/Package.java index 59470da..b3deb96 100644 --- a/src/main/java/fr/packageviewer/ArchParser/Package.java +++ b/src/main/java/fr/packageviewer/ArchParser/Package.java @@ -14,4 +14,8 @@ public class Package extends SearchedPackage { this.deps = deps; } + @Override + public String toString() { + return "Package{SearchedPackage{%s},deps=%s}".formatted(super.toString(), deps); + } } diff --git a/src/main/java/fr/packageviewer/ArchParser/SearchedPackage.java b/src/main/java/fr/packageviewer/ArchParser/SearchedPackage.java index a761e9f..b02ba94 100644 --- a/src/main/java/fr/packageviewer/ArchParser/SearchedPackage.java +++ b/src/main/java/fr/packageviewer/ArchParser/SearchedPackage.java @@ -29,6 +29,8 @@ public class SearchedPackage { this.description = desciption; } - - + @Override + public String toString() { + return "SearchedPackage{name=%s,version=%s,repo=%s,description=%s}".formatted(name, version, repo, description); + } } From 1f35e337ba8ad21b9a745a3ca37e0eba12386065 Mon Sep 17 00:00:00 2001 From: Thomas Rubini <74205383+ThomasRubini@users.noreply.github.com> Date: Mon, 12 Dec 2022 16:39:48 +0100 Subject: [PATCH 3/6] Process requests in async mode in Arch + added logs to handle bad URLs --- .../packageviewer/ArchParser/ArchParser.java | 105 ++++++++++++------ 1 file changed, 70 insertions(+), 35 deletions(-) diff --git a/src/main/java/fr/packageviewer/ArchParser/ArchParser.java b/src/main/java/fr/packageviewer/ArchParser/ArchParser.java index a57e20d..26262af 100644 --- a/src/main/java/fr/packageviewer/ArchParser/ArchParser.java +++ b/src/main/java/fr/packageviewer/ArchParser/ArchParser.java @@ -2,33 +2,36 @@ package fr.packageviewer.ArchParser; import java.io.IOException; import java.net.URI; +import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.net.http.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.logging.Level; +import java.util.logging.Logger; + +import fr.packageviewer.LoggerManager; import org.json.*; public class ArchParser { + private static final Logger logger = LoggerManager.getLogger("ArchParser"); + /** * Will return the String json of the package from the Arch Linux API * @param packageName the package name to get the json from * @return json of the package */ - public String getPackageFromAPI(String packageName){ + public CompletableFuture> getPackageFromAPI(String packageName) { // create a new http client HttpClient client = HttpClient.newHttpClient(); // and create its url HttpRequest request = HttpRequest.newBuilder(URI.create("https://archlinux.org/packages/search/json/?name="+packageName)).build(); // send its url and return the string given - try { - return client.send(request, HttpResponse.BodyHandlers.ofString()).body(); - } catch (IOException|InterruptedException e) { - e.printStackTrace(); - } - // if there's an error, return an empty string - return ""; + return client.sendAsync(request, HttpResponse.BodyHandlers.ofString()); } @@ -79,40 +82,72 @@ public class ArchParser { * @param depth depth to search dependencies * @return new Package */ - public Package getPackageTree(String packageName, int depth){ - String name, version, repo, description; - List deps = new ArrayList<>(); + public CompletableFuture getPackageTree(String packageName, int depth) { // parse the json - JSONObject json = new JSONObject(getPackageFromAPI(packageName)); + var futurePackage = new CompletableFuture(); - JSONArray resultsArrayJson = json.getJSONArray("results"); - if(resultsArrayJson.length()==0){ - // unknown package, probably an abstract dependency - return null; + logger.fine("Querying package %s from API... (depth=%s)".formatted(packageName, depth)); + + CompletableFuture> futureRequest; + try{ + futureRequest = getPackageFromAPI(packageName); + }catch(IllegalArgumentException e){ + logger.warning("Caught exception for package %s :\n%s".formatted(packageName, e)); + return CompletableFuture.completedFuture(null); } - JSONObject resultJson = json.getJSONArray("results").getJSONObject(0); + futureRequest.thenAccept(result->{ + List deps = new ArrayList<>(); + String name, version, repo, description; - // get infos except dependencies - name = resultJson.getString("pkgname"); - version = resultJson.getString("pkgver"); - repo = resultJson.getString("repo"); - description = resultJson.getString("pkgdesc"); + JSONObject json = new JSONObject(result.body()); - // if we're at the maximum depth, return the package without its dependencies - if(depth==0){ - return new Package(name, version, repo, description, Collections.emptyList()); - } else { - // iterate for every package in the list - for (Object depPackageNameObj : resultJson.getJSONArray("depends")) { - // convert object into String - String depPackageName = (String) depPackageNameObj; - // add package into Package List - deps.add(getPackageTree(depPackageName, depth - 1)); + JSONArray resultsArrayJson = json.getJSONArray("results"); + if(resultsArrayJson.length()==0){ + // unknown package, probably an abstract dependency + logger.fine("Completing callback INVALID for package %s (depth=%s)".formatted(packageName, depth)); + futurePackage.complete(null); } + JSONObject resultJson = json.getJSONArray("results").getJSONObject(0); - // TODO this doesn't seem clean - return new Package(name, version, repo, description, deps); - } + // get infos except dependencies + name = resultJson.getString("pkgname"); + version = resultJson.getString("pkgver"); + repo = resultJson.getString("repo"); + description = resultJson.getString("pkgdesc"); + + // if we're at the maximum depth, return the package without its dependencies + if(depth==0){ + logger.fine("Completing callback NODEP for package %s (depth=%s)".formatted(packageName, depth)); + futurePackage.complete(new Package(name, version, repo, description, Collections.emptyList())); + } else { + // iterate for every package in the list + List> futureDeps = new ArrayList<>(); + for (Object depPackageNameObj : resultJson.getJSONArray("depends")) { + // convert object into String + String depPackageName = (String) depPackageNameObj; + // add package into Package List + futureDeps.add(getPackageTree(depPackageName, depth - 1)); + } + for(CompletableFuture future : futureDeps){ + try { + deps.add(future.get()); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } + } + + // TODO this doesn't seem clean + logger.fine("Completing callback DEPS for package %s (depth=%s)".formatted(packageName, depth)); + futurePackage.complete(new Package(name, version, repo, description, deps)); + } + }).exceptionally((e2->{ + logger.warning("Error while fetching package %s (depth=%s) from the API : \n%s".formatted(packageName, depth, e2)); + e2.printStackTrace(); + futurePackage.complete(null); + return null; + })); + + return futurePackage; } } From 1c9fe51a535b3598e0a63f359032fe14b03ebc9e Mon Sep 17 00:00:00 2001 From: Thomas Rubini <74205383+ThomasRubini@users.noreply.github.com> Date: Mon, 12 Dec 2022 16:54:32 +0100 Subject: [PATCH 4/6] Refactored project --- .../ArchDistribution.java} | 8 ++++---- .../fr/packageviewer/distribution/Distribution.java | 12 ++++++++++++ .../packageviewer/{ArchParser => pack}/Package.java | 2 +- .../{ArchParser => pack}/SearchedPackage.java | 2 +- 4 files changed, 18 insertions(+), 6 deletions(-) rename src/main/java/fr/packageviewer/{ArchParser/ArchParser.java => distribution/ArchDistribution.java} (97%) create mode 100644 src/main/java/fr/packageviewer/distribution/Distribution.java rename src/main/java/fr/packageviewer/{ArchParser => pack}/Package.java (93%) rename src/main/java/fr/packageviewer/{ArchParser => pack}/SearchedPackage.java (95%) diff --git a/src/main/java/fr/packageviewer/ArchParser/ArchParser.java b/src/main/java/fr/packageviewer/distribution/ArchDistribution.java similarity index 97% rename from src/main/java/fr/packageviewer/ArchParser/ArchParser.java rename to src/main/java/fr/packageviewer/distribution/ArchDistribution.java index 26262af..a6203b5 100644 --- a/src/main/java/fr/packageviewer/ArchParser/ArchParser.java +++ b/src/main/java/fr/packageviewer/distribution/ArchDistribution.java @@ -1,8 +1,7 @@ -package fr.packageviewer.ArchParser; +package fr.packageviewer.distribution; import java.io.IOException; import java.net.URI; -import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -10,13 +9,14 @@ import java.util.List; import java.net.http.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; -import java.util.logging.Level; import java.util.logging.Logger; import fr.packageviewer.LoggerManager; +import fr.packageviewer.pack.Package; +import fr.packageviewer.pack.SearchedPackage; import org.json.*; -public class ArchParser { +public class ArchDistribution implements Distribution { private static final Logger logger = LoggerManager.getLogger("ArchParser"); diff --git a/src/main/java/fr/packageviewer/distribution/Distribution.java b/src/main/java/fr/packageviewer/distribution/Distribution.java new file mode 100644 index 0000000..33d6d47 --- /dev/null +++ b/src/main/java/fr/packageviewer/distribution/Distribution.java @@ -0,0 +1,12 @@ +package fr.packageviewer.distribution; + +import fr.packageviewer.pack.Package; +import fr.packageviewer.pack.SearchedPackage; + +import java.util.List; +import java.util.concurrent.CompletableFuture; + +public interface Distribution { + List searchPackage(String packageName); + CompletableFuture getPackageTree(String packageName, int depth); +} diff --git a/src/main/java/fr/packageviewer/ArchParser/Package.java b/src/main/java/fr/packageviewer/pack/Package.java similarity index 93% rename from src/main/java/fr/packageviewer/ArchParser/Package.java rename to src/main/java/fr/packageviewer/pack/Package.java index b3deb96..cc0cf3a 100644 --- a/src/main/java/fr/packageviewer/ArchParser/Package.java +++ b/src/main/java/fr/packageviewer/pack/Package.java @@ -1,4 +1,4 @@ -package fr.packageviewer.ArchParser; +package fr.packageviewer.pack; import java.util.List; diff --git a/src/main/java/fr/packageviewer/ArchParser/SearchedPackage.java b/src/main/java/fr/packageviewer/pack/SearchedPackage.java similarity index 95% rename from src/main/java/fr/packageviewer/ArchParser/SearchedPackage.java rename to src/main/java/fr/packageviewer/pack/SearchedPackage.java index b02ba94..868801e 100644 --- a/src/main/java/fr/packageviewer/ArchParser/SearchedPackage.java +++ b/src/main/java/fr/packageviewer/pack/SearchedPackage.java @@ -1,4 +1,4 @@ -package fr.packageviewer.ArchParser; +package fr.packageviewer.pack; public class SearchedPackage { private final String name; From 5cbf5149219fc5fc95c7fdb5e5e637a53bb74aa1 Mon Sep 17 00:00:00 2001 From: Thomas Rubini <74205383+ThomasRubini@users.noreply.github.com> Date: Mon, 12 Dec 2022 21:37:02 +0100 Subject: [PATCH 5/6] CI to build the project jar --- .github/workflows/build.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..7490622 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,23 @@ +name: Build + +on: + push: + branches: ['*'] + +jobs: + build: + name: Build + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Build + run: | + ./gradlew jar + + - uses: actions/upload-artifact@v3 + with: + name: PackageViewer jar + path: ./build/libs/PackageViewer*.jar From 4b1c2bf45ad6711a819d12142d15846624e25afb Mon Sep 17 00:00:00 2001 From: Thomas Rubini <74205383+ThomasRubini@users.noreply.github.com> Date: Mon, 12 Dec 2022 21:42:48 +0100 Subject: [PATCH 6/6] set minimum Java version to 13 --- build.gradle | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/build.gradle b/build.gradle index 3145cd7..c7f4af3 100644 --- a/build.gradle +++ b/build.gradle @@ -8,6 +8,11 @@ version '1.0-SNAPSHOT' mainClassName = 'fr.packageviewer.Main' +java { + sourceCompatibility = JavaVersion.VERSION_13 + targetCompatibility = JavaVersion.VERSION_13 +} + jar{ manifest { attributes(