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( diff --git a/src/main/java/fr/packageviewer/ArchParser/ArchParser.java b/src/main/java/fr/packageviewer/ArchParser/ArchParser.java deleted file mode 100644 index a57e20d..0000000 --- a/src/main/java/fr/packageviewer/ArchParser/ArchParser.java +++ /dev/null @@ -1,118 +0,0 @@ -package fr.packageviewer.ArchParser; - -import java.io.IOException; -import java.net.URI; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import java.net.http.*; -import org.json.*; - -public class 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){ - // 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 ""; - } - - -/** - * Search for a package and return a list of packages - * @param packageName the package name to search - * @return - */ - public List searchPackage(String packageName){ - HttpClient client = HttpClient.newHttpClient(); - HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create("https://archlinux.org/packages/search/json/?q="+packageName)) - .build(); - - HttpResponse response; - try{ - response = client.send(request, HttpResponse.BodyHandlers.ofString()); - }catch(IOException|InterruptedException e){ - e.printStackTrace(); - return null; - } - - JSONObject json = new JSONObject(response.body()); - - List searchedPackagesList = new ArrayList<>(); - - // iterate for every package in the list - for (Object searchResultObj : json.getJSONArray("results")) { - // convert object into String - JSONObject searchResultJson = (JSONObject) searchResultObj; - // add package into to list - searchedPackagesList.add(new SearchedPackage( - searchResultJson.getString("pkgname"), - searchResultJson.getString("pkgver"), - searchResultJson.getString("repo"), - searchResultJson.getString("pkgdesc") - )); - } - - return searchedPackagesList; - - } - - - /** - * Will generate a dependencies tree of depth 'depth' given the package name - * @param packageName the package name to search - * @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<>(); - - // parse the json - JSONObject json = new JSONObject(getPackageFromAPI(packageName)); - - JSONArray resultsArrayJson = json.getJSONArray("results"); - if(resultsArrayJson.length()==0){ - // unknown package, probably an abstract dependency - return null; - } - JSONObject resultJson = json.getJSONArray("results").getJSONObject(0); - - // 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){ - 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)); - } - - // TODO this doesn't seem clean - return new Package(name, version, repo, description, deps); - } - } -} diff --git a/src/main/java/fr/packageviewer/ArchParser/Package.java b/src/main/java/fr/packageviewer/ArchParser/Package.java deleted file mode 100644 index 321555e..0000000 --- a/src/main/java/fr/packageviewer/ArchParser/Package.java +++ /dev/null @@ -1,13 +0,0 @@ -package fr.packageviewer.ArchParser; - -import java.util.List; - -public class Package extends SearchedPackage { - List deps; - - public Package(String name, String version, String repo, String description, List deps) { - super(name, version, repo, description); - this.deps = deps; - } - -} diff --git a/src/main/java/fr/packageviewer/ArchParser/SearchedPackage.java b/src/main/java/fr/packageviewer/ArchParser/SearchedPackage.java deleted file mode 100644 index 205756d..0000000 --- a/src/main/java/fr/packageviewer/ArchParser/SearchedPackage.java +++ /dev/null @@ -1,16 +0,0 @@ -package fr.packageviewer.ArchParser; - -public class SearchedPackage { - String name; - String version; - String repo; - String description; - - public SearchedPackage(String name, String version, String repo, String desciption) { - this.name = name; - this.version = version; - this.repo = repo; - this.description = desciption; - } - -} diff --git a/src/main/java/fr/packageviewer/distribution/ArchDistribution.java b/src/main/java/fr/packageviewer/distribution/ArchDistribution.java new file mode 100644 index 0000000..a6203b5 --- /dev/null +++ b/src/main/java/fr/packageviewer/distribution/ArchDistribution.java @@ -0,0 +1,153 @@ +package fr.packageviewer.distribution; + +import java.io.IOException; +import java.net.URI; +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.Logger; + +import fr.packageviewer.LoggerManager; +import fr.packageviewer.pack.Package; +import fr.packageviewer.pack.SearchedPackage; +import org.json.*; + +public class ArchDistribution implements Distribution { + + 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 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 + return client.sendAsync(request, HttpResponse.BodyHandlers.ofString()); + } + + +/** + * Search for a package and return a list of packages + * @param packageName the package name to search + * @return + */ + public List searchPackage(String packageName){ + HttpClient client = HttpClient.newHttpClient(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create("https://archlinux.org/packages/search/json/?q="+packageName)) + .build(); + + HttpResponse response; + try{ + response = client.send(request, HttpResponse.BodyHandlers.ofString()); + }catch(IOException|InterruptedException e){ + e.printStackTrace(); + return null; + } + + JSONObject json = new JSONObject(response.body()); + + List searchedPackagesList = new ArrayList<>(); + + // iterate for every package in the list + for (Object searchResultObj : json.getJSONArray("results")) { + // convert object into String + JSONObject searchResultJson = (JSONObject) searchResultObj; + // add package into to list + searchedPackagesList.add(new SearchedPackage( + searchResultJson.getString("pkgname"), + searchResultJson.getString("pkgver"), + searchResultJson.getString("repo"), + searchResultJson.getString("pkgdesc") + )); + } + + return searchedPackagesList; + + } + + + /** + * Will generate a dependencies tree of depth 'depth' given the package name + * @param packageName the package name to search + * @param depth depth to search dependencies + * @return new Package + */ + public CompletableFuture getPackageTree(String packageName, int depth) { + + // parse the json + var futurePackage = new CompletableFuture(); + + 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); + } + futureRequest.thenAccept(result->{ + List deps = new ArrayList<>(); + String name, version, repo, description; + + JSONObject json = new JSONObject(result.body()); + + 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); + + // 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; + } +} 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/pack/Package.java b/src/main/java/fr/packageviewer/pack/Package.java new file mode 100644 index 0000000..cc0cf3a --- /dev/null +++ b/src/main/java/fr/packageviewer/pack/Package.java @@ -0,0 +1,21 @@ +package fr.packageviewer.pack; + +import java.util.List; + +public class Package extends SearchedPackage { + 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); + 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/pack/SearchedPackage.java b/src/main/java/fr/packageviewer/pack/SearchedPackage.java new file mode 100644 index 0000000..868801e --- /dev/null +++ b/src/main/java/fr/packageviewer/pack/SearchedPackage.java @@ -0,0 +1,36 @@ +package fr.packageviewer.pack; + +public class SearchedPackage { + 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; + this.version = version; + this.repo = repo; + this.description = desciption; + } + + @Override + public String toString() { + return "SearchedPackage{name=%s,version=%s,repo=%s,description=%s}".formatted(name, version, repo, description); + } +}