From fd8c373c0347564a600dc399cb3e76744861ed61 Mon Sep 17 00:00:00 2001 From: Mikhail Fedoseev Date: Mon, 3 Mar 2025 22:37:55 +0400 Subject: [PATCH 01/10] Support for additional npm dependencies --- .../cli/command/ExportNpmCommand.java | 17 +++++++- .../cli/command/ResolveNpmCommand.java | 40 +++++++++++++++++++ .../version-2-5-0/package-lock.json | 25 ++++++++++++ 3 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 deptool/src/main/resources/jmix-dependencies/additional-dependencies/version-2-5-0/package-lock.json diff --git a/deptool/src/main/java/io/jmix/dependency/cli/command/ExportNpmCommand.java b/deptool/src/main/java/io/jmix/dependency/cli/command/ExportNpmCommand.java index e0eaec6..1340011 100644 --- a/deptool/src/main/java/io/jmix/dependency/cli/command/ExportNpmCommand.java +++ b/deptool/src/main/java/io/jmix/dependency/cli/command/ExportNpmCommand.java @@ -62,8 +62,21 @@ protected void installNodeTgzDownloader() { protected void downloadNpmArchives(String packageLockFileLocation, String directory) { log.info("-= Download tgz-archives =-"); - String command = "npx download-tgz package-lock " + packageLockFileLocation + " --directory=" + directory; - executeCommand(downloaderDir, command); + String downloadCommandTemplate = "npx download-tgz package-lock %s --directory=" + directory; + executeCommand(downloaderDir, downloadCommandTemplate.formatted(packageLockFileLocation)); + + try { + Path additionalDependenciesPackageLockJsonPath = Paths.get(resolverProjectPath + + "/additional-dependencies/package-lock.json").toAbsolutePath().normalize(); + + if (additionalDependenciesPackageLockJsonPath.toFile().exists()) { + executeCommand(downloaderDir, + downloadCommandTemplate.formatted( + additionalDependenciesPackageLockJsonPath.toString())); + } + } catch (Exception e) { + log.warn("Error when trying to download additional dependencies", e); + } } protected void copyPackageLock() { diff --git a/deptool/src/main/java/io/jmix/dependency/cli/command/ResolveNpmCommand.java b/deptool/src/main/java/io/jmix/dependency/cli/command/ResolveNpmCommand.java index c904c16..5c83bc5 100644 --- a/deptool/src/main/java/io/jmix/dependency/cli/command/ResolveNpmCommand.java +++ b/deptool/src/main/java/io/jmix/dependency/cli/command/ResolveNpmCommand.java @@ -11,6 +11,7 @@ import java.io.File; import java.io.IOException; +import java.net.URL; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Comparator; @@ -76,6 +77,7 @@ public void run() { vaadinClean(jmixGradleClient); copyStubPackageLock(); resolveDependencies(jmixGradleClient); + resolveAdditionalDependencies(); } protected void vaadinClean(JmixGradleClient jmixGradleClient) { @@ -153,4 +155,42 @@ protected void resolveDependencies(JmixGradleClient jmixGradleClient) { log.info(result); } } + + private void resolveAdditionalDependencies() { + if (jmixVersion == null) { + return; + } + + try { + File resolverProjectFile = new File(resolverProjectPath); + File additionalDependenciesDir = new File(resolverProjectFile.getAbsolutePath() + "/additional-dependencies"); + FileUtils.cleanDirectory(additionalDependenciesDir); + + String additionalDependenciesDirPath = "version-" + jmixVersion.replace(".", "-"); + URL additionalDependenciesUrl = getClass().getClassLoader().getResource("jmix-dependencies/additional-dependencies/" + additionalDependenciesDirPath + "/package-lock.json"); + if (additionalDependenciesUrl == null) { + return; + } + + File additionalDependenciesFile = new File(additionalDependenciesUrl.toURI()); + if (!additionalDependenciesFile.exists()) { + return; + } + + log.info("-= Resolve additional dependencies =-"); + + if (!resolverProjectFile.exists()) { + return; + } + + log.info("-= Copy additional dependencies package-lock.json =-"); + try { + FileUtils.copyFileToDirectory(additionalDependenciesFile, additionalDependenciesDir); + } catch (IOException e) { + throw new RuntimeException("Unable to copy additional dependencies package-lock.json", e); + } + } catch (Exception e) { + log.info("Error when trying to download additional dependencies", e); + } + } } diff --git a/deptool/src/main/resources/jmix-dependencies/additional-dependencies/version-2-5-0/package-lock.json b/deptool/src/main/resources/jmix-dependencies/additional-dependencies/version-2-5-0/package-lock.json new file mode 100644 index 0000000..eccafc4 --- /dev/null +++ b/deptool/src/main/resources/jmix-dependencies/additional-dependencies/version-2-5-0/package-lock.json @@ -0,0 +1,25 @@ +{ + "name": "no-name", + "lockfileVersion": 1, + "requires": true, + "packages": { + "": { + "name": "no-name", + "license": "UNLICENSED", + "dependencies": { + "@vaadin/router": "2.0.0" + } + } + }, + "node_modules/@vaadin/router": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@vaadin/router/-/router-2.0.0.tgz", + "integrity": "sha512-IjOlzuUsrVhfBId+ypcdDLM3+GZHo64DUlkr8IjFe04A4kMvt0zVFIpPH03X52/tMiwyYOF0Sw6p53DXkWiZcA==", + "dependencies": { + "@vaadin/vaadin-usage-statistics": "^2.1.2", + "path-to-regexp": "^6.3.0", + "type-fest": "^4.26.1" + } + }, + "dependencies": {} +} \ No newline at end of file From 4deafbf3e7a48c40fb7f0c3b070f2d210a7a1b01 Mon Sep 17 00:00:00 2001 From: Mikhail Fedoseev Date: Tue, 4 Mar 2025 17:58:26 +0400 Subject: [PATCH 02/10] Support for additional npm dependencies --- .../cli/command/ExportNpmCommand.java | 24 +++++----- .../cli/command/ResolveNpmCommand.java | 46 ++++++++++--------- .../version-2-5-0/package-lock.json | 29 +++++------- 3 files changed, 48 insertions(+), 51 deletions(-) diff --git a/deptool/src/main/java/io/jmix/dependency/cli/command/ExportNpmCommand.java b/deptool/src/main/java/io/jmix/dependency/cli/command/ExportNpmCommand.java index 1340011..ca811ba 100644 --- a/deptool/src/main/java/io/jmix/dependency/cli/command/ExportNpmCommand.java +++ b/deptool/src/main/java/io/jmix/dependency/cli/command/ExportNpmCommand.java @@ -49,7 +49,8 @@ public void run() { log.info("package-lock.json file: {}", packageLockJsonPath); installNodeTgzDownloader(); - downloadNpmArchives(packageLockJsonPath.toString(), targetDirectoryPath.toString()); + downloadAdditionalNpmArchives(targetDirectoryPath.toString()); + downloadMainNpmArchives(packageLockJsonPath.toString(), targetDirectoryPath.toString()); copyPackageLock(); log.info("Export completed successfully"); @@ -60,19 +61,18 @@ protected void installNodeTgzDownloader() { executeCommand(downloaderDir, "npm install node-tgz-downloader"); } - protected void downloadNpmArchives(String packageLockFileLocation, String directory) { - log.info("-= Download tgz-archives =-"); - String downloadCommandTemplate = "npx download-tgz package-lock %s --directory=" + directory; - executeCommand(downloaderDir, downloadCommandTemplate.formatted(packageLockFileLocation)); + private void downloadMainNpmArchives(String packageLockFileLocation, String directory) { + log.info("-= Download main tgz-archives =-"); + executeCommand(downloaderDir, "npx download-tgz package-lock " + packageLockFileLocation + " --directory=" + directory); + } + private void downloadAdditionalNpmArchives(String directory) { try { - Path additionalDependenciesPackageLockJsonPath = Paths.get(resolverProjectPath - + "/additional-dependencies/package-lock.json").toAbsolutePath().normalize(); - - if (additionalDependenciesPackageLockJsonPath.toFile().exists()) { - executeCommand(downloaderDir, - downloadCommandTemplate.formatted( - additionalDependenciesPackageLockJsonPath.toString())); + String additionalDependenciesDirPath = resolverProjectPath + "/additional-dependencies"; + Path packageLockPath = Paths.get(additionalDependenciesDirPath, "package-lock.json").toAbsolutePath().normalize(); + if (packageLockPath.toFile().exists()) { + log.info("-= Download additional tgz-archives =-"); + executeCommand(downloaderDir, "npx download-tgz package-lock " + packageLockPath + " --directory=" + directory); } } catch (Exception e) { log.warn("Error when trying to download additional dependencies", e); diff --git a/deptool/src/main/java/io/jmix/dependency/cli/command/ResolveNpmCommand.java b/deptool/src/main/java/io/jmix/dependency/cli/command/ResolveNpmCommand.java index 5c83bc5..4dd8e2a 100644 --- a/deptool/src/main/java/io/jmix/dependency/cli/command/ResolveNpmCommand.java +++ b/deptool/src/main/java/io/jmix/dependency/cli/command/ResolveNpmCommand.java @@ -11,7 +11,7 @@ import java.io.File; import java.io.IOException; -import java.net.URL; +import java.io.InputStream; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Comparator; @@ -162,35 +162,39 @@ private void resolveAdditionalDependencies() { } try { - File resolverProjectFile = new File(resolverProjectPath); - File additionalDependenciesDir = new File(resolverProjectFile.getAbsolutePath() + "/additional-dependencies"); - FileUtils.cleanDirectory(additionalDependenciesDir); - - String additionalDependenciesDirPath = "version-" + jmixVersion.replace(".", "-"); - URL additionalDependenciesUrl = getClass().getClassLoader().getResource("jmix-dependencies/additional-dependencies/" + additionalDependenciesDirPath + "/package-lock.json"); - if (additionalDependenciesUrl == null) { + File additionalDependenciesDir = Paths.get(resolverProjectPath + "/additional-dependencies").toAbsolutePath().normalize().toFile(); + if (additionalDependenciesDir.exists()) { + FileUtils.cleanDirectory(additionalDependenciesDir); + } else if (!additionalDependenciesDir.mkdir()) { return; } - File additionalDependenciesFile = new File(additionalDependenciesUrl.toURI()); - if (!additionalDependenciesFile.exists()) { - return; - } + String versionDirName = "version-" + jmixVersion.replace(".", "-"); + try (InputStream packageLockJsonContent = getAdditionalDependenciesFile(versionDirName, "package-lock.json"); + InputStream packageJsonContent = getAdditionalDependenciesFile(versionDirName, "package.json")) { + if (packageLockJsonContent == null || packageJsonContent == null) { + return; + } - log.info("-= Resolve additional dependencies =-"); + log.info("-= Resolve additional dependencies =-"); - if (!resolverProjectFile.exists()) { - return; + try { + File packageLockJson = new File(additionalDependenciesDir, "package-lock.json"); + packageLockJson.createNewFile(); + log.info("-= Copy additional dependencies package-lock.json =-"); + FileUtils.copyInputStreamToFile(packageLockJsonContent, packageLockJson); + } catch (IOException e) { + throw new RuntimeException("Unable to copy additional dependencies package-lock.json", e); + } } - log.info("-= Copy additional dependencies package-lock.json =-"); - try { - FileUtils.copyFileToDirectory(additionalDependenciesFile, additionalDependenciesDir); - } catch (IOException e) { - throw new RuntimeException("Unable to copy additional dependencies package-lock.json", e); - } } catch (Exception e) { log.info("Error when trying to download additional dependencies", e); } } + + private InputStream getAdditionalDependenciesFile(String versionDirName, String filename) { + return getClass().getClassLoader().getResourceAsStream( + "jmix-dependencies/additional-dependencies/" + versionDirName + "/" + filename); + } } diff --git a/deptool/src/main/resources/jmix-dependencies/additional-dependencies/version-2-5-0/package-lock.json b/deptool/src/main/resources/jmix-dependencies/additional-dependencies/version-2-5-0/package-lock.json index eccafc4..c135af3 100644 --- a/deptool/src/main/resources/jmix-dependencies/additional-dependencies/version-2-5-0/package-lock.json +++ b/deptool/src/main/resources/jmix-dependencies/additional-dependencies/version-2-5-0/package-lock.json @@ -1,25 +1,18 @@ { "name": "no-name", - "lockfileVersion": 1, + "lockfileVersion": 3, "requires": true, "packages": { - "": { - "name": "no-name", - "license": "UNLICENSED", + "node_modules/@vaadin/router": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@vaadin/router/-/router-2.0.0.tgz", + "integrity": "sha512-IjOlzuUsrVhfBId+ypcdDLM3+GZHo64DUlkr8IjFe04A4kMvt0zVFIpPH03X52/tMiwyYOF0Sw6p53DXkWiZcA==", + "license": "Apache-2.0", "dependencies": { - "@vaadin/router": "2.0.0" + "@vaadin/vaadin-usage-statistics": "^2.1.2", + "path-to-regexp": "^6.3.0", + "type-fest": "^4.26.1" } } - }, - "node_modules/@vaadin/router": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@vaadin/router/-/router-2.0.0.tgz", - "integrity": "sha512-IjOlzuUsrVhfBId+ypcdDLM3+GZHo64DUlkr8IjFe04A4kMvt0zVFIpPH03X52/tMiwyYOF0Sw6p53DXkWiZcA==", - "dependencies": { - "@vaadin/vaadin-usage-statistics": "^2.1.2", - "path-to-regexp": "^6.3.0", - "type-fest": "^4.26.1" - } - }, - "dependencies": {} -} \ No newline at end of file + } +} From f0638a15a55295b224da634abed5151e7379d9a9 Mon Sep 17 00:00:00 2001 From: Mikhail Fedoseev Date: Tue, 4 Mar 2025 18:20:55 +0400 Subject: [PATCH 03/10] Support for additional npm dependencies --- .../io/jmix/dependency/cli/command/ResolveNpmCommand.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/deptool/src/main/java/io/jmix/dependency/cli/command/ResolveNpmCommand.java b/deptool/src/main/java/io/jmix/dependency/cli/command/ResolveNpmCommand.java index 4dd8e2a..d07c97a 100644 --- a/deptool/src/main/java/io/jmix/dependency/cli/command/ResolveNpmCommand.java +++ b/deptool/src/main/java/io/jmix/dependency/cli/command/ResolveNpmCommand.java @@ -170,9 +170,8 @@ private void resolveAdditionalDependencies() { } String versionDirName = "version-" + jmixVersion.replace(".", "-"); - try (InputStream packageLockJsonContent = getAdditionalDependenciesFile(versionDirName, "package-lock.json"); - InputStream packageJsonContent = getAdditionalDependenciesFile(versionDirName, "package.json")) { - if (packageLockJsonContent == null || packageJsonContent == null) { + try (InputStream packageLockContent = getAdditionalDependenciesFile(versionDirName, "package-lock.json")) { + if (packageLockContent == null) { return; } @@ -182,7 +181,7 @@ private void resolveAdditionalDependencies() { File packageLockJson = new File(additionalDependenciesDir, "package-lock.json"); packageLockJson.createNewFile(); log.info("-= Copy additional dependencies package-lock.json =-"); - FileUtils.copyInputStreamToFile(packageLockJsonContent, packageLockJson); + FileUtils.copyInputStreamToFile(packageLockContent, packageLockJson); } catch (IOException e) { throw new RuntimeException("Unable to copy additional dependencies package-lock.json", e); } From e2c2eb0b2674115fb881a283f32eab925d6ba776 Mon Sep 17 00:00:00 2001 From: Mikhail Fedoseev Date: Wed, 5 Mar 2025 18:57:35 +0400 Subject: [PATCH 04/10] Support for additional npm dependencies --- README.md | 2 + .../cli/command/ResolveNpmCommand.java | 13 ++-- .../cli/dependency/JmixDependencies.java | 66 ++++++++++++++++-- .../AdditionalDependencyFileType.java | 29 ++++++++ .../additional/AdditionalDependencyType.java | 68 +++++++++++++++++++ .../npm/2.5}/package-lock.json | 0 6 files changed, 166 insertions(+), 12 deletions(-) create mode 100644 deptool/src/main/java/io/jmix/dependency/cli/dependency/additional/AdditionalDependencyFileType.java create mode 100644 deptool/src/main/java/io/jmix/dependency/cli/dependency/additional/AdditionalDependencyType.java rename deptool/src/main/resources/jmix-dependencies/{additional-dependencies/version-2-5-0 => additional/npm/2.5}/package-lock.json (100%) diff --git a/README.md b/README.md index 6d86af9..de4113f 100644 --- a/README.md +++ b/README.md @@ -311,6 +311,8 @@ The `deptool` utility resolves dependencies by invocation of gradle tasks in the The `JmixNpmDependenciesPlugin` adds the `resolveNpmDependencies` task. This task is invoked by the `deptool` utility for dependencies resolution. +Also, if you need to declare additional npm dependencies, you can add or edit `package-lock.json` file in [special directory](./deptool/src/main/resources/jmix-dependencies/additional/npm) for a suitable Jmix version. + ```shell ./gradlew resolveDependencies \ --dependency io.jmix.flowui:jmix-flowui \ diff --git a/deptool/src/main/java/io/jmix/dependency/cli/command/ResolveNpmCommand.java b/deptool/src/main/java/io/jmix/dependency/cli/command/ResolveNpmCommand.java index d07c97a..fa33e49 100644 --- a/deptool/src/main/java/io/jmix/dependency/cli/command/ResolveNpmCommand.java +++ b/deptool/src/main/java/io/jmix/dependency/cli/command/ResolveNpmCommand.java @@ -17,6 +17,8 @@ import java.util.Comparator; import java.util.List; +import static io.jmix.dependency.cli.dependency.additional.AdditionalDependencyFileType.PACKAGE_LOCK; + @Parameters(commandDescription = "Resolves Npm dependencies") public class ResolveNpmCommand implements BaseCommand { @@ -162,15 +164,15 @@ private void resolveAdditionalDependencies() { } try { - File additionalDependenciesDir = Paths.get(resolverProjectPath + "/additional-dependencies").toAbsolutePath().normalize().toFile(); + File additionalDependenciesDir = Paths.get(resolverProjectPath, + "additional-dependencies").toAbsolutePath().normalize().toFile(); if (additionalDependenciesDir.exists()) { FileUtils.cleanDirectory(additionalDependenciesDir); } else if (!additionalDependenciesDir.mkdir()) { return; } - String versionDirName = "version-" + jmixVersion.replace(".", "-"); - try (InputStream packageLockContent = getAdditionalDependenciesFile(versionDirName, "package-lock.json")) { + try (InputStream packageLockContent = PACKAGE_LOCK.findFileContent(jmixVersion)) { if (packageLockContent == null) { return; } @@ -179,6 +181,7 @@ private void resolveAdditionalDependencies() { try { File packageLockJson = new File(additionalDependenciesDir, "package-lock.json"); + //noinspection ResultOfMethodCallIgnored packageLockJson.createNewFile(); log.info("-= Copy additional dependencies package-lock.json =-"); FileUtils.copyInputStreamToFile(packageLockContent, packageLockJson); @@ -192,8 +195,4 @@ private void resolveAdditionalDependencies() { } } - private InputStream getAdditionalDependenciesFile(String versionDirName, String filename) { - return getClass().getClassLoader().getResourceAsStream( - "jmix-dependencies/additional-dependencies/" + versionDirName + "/" + filename); - } } diff --git a/deptool/src/main/java/io/jmix/dependency/cli/dependency/JmixDependencies.java b/deptool/src/main/java/io/jmix/dependency/cli/dependency/JmixDependencies.java index e4a0d68..bc3c39b 100644 --- a/deptool/src/main/java/io/jmix/dependency/cli/dependency/JmixDependencies.java +++ b/deptool/src/main/java/io/jmix/dependency/cli/dependency/JmixDependencies.java @@ -48,19 +48,75 @@ private static Set _getVersionSpecificDependencies(String version, boole dependencies.addAll(commercialDependencies); } return dependencies; - } catch (IOException e) { - throw new RuntimeException(e); - } catch (DocumentException e) { + } catch (IOException | DocumentException e) { throw new RuntimeException(e); } } /** - * Extracts minor version from version string, e.g. 1.4.2 -> 1.4 + * Extracts a minor version from version string. + * Examples: + *
    + *
  • null -> null
  • + *
  • "" -> ""
  • + *
  • abc -> ""
  • + *
  • 1.4.2 -> 1.4
  • + *
  • 1.4 -> 1.4
  • + *
  • 1 -> 1.0
  • + *
*/ - private static String getMinorVersion(String jmixVersion) { + public static String getMinorVersion(String jmixVersion) { + if (jmixVersion == null) { + return null; + } + String[] parts = jmixVersion.split("\\."); + if (parts.length < 2) { + if (parts.length == 0) { + return ""; + } else { + return parts[0] + "." + 0; + } + } + return parts[0] + "." + parts[1]; } + /** + * Extracts a patch from version string. + * Examples: + *
    + *
  • null -> null
  • + *
  • "" -> ""
  • + *
  • abc -> ""
  • + *
  • 1.4.2 -> 2
  • + *
  • 1.4 -> 0
  • + *
  • 1 -> 0
  • + *
+ */ + public static String getPatchVersion(String jmixVersion) { + if (jmixVersion == null) { + return null; + } + + String[] parts = jmixVersion.split("\\."); + if (parts.length < 3) { + if (parts.length == 0) { + return ""; + } else { + return "0"; + } + } + + return parts[2]; + } + + public static boolean hasPatch(String jmixVersion) { + if (jmixVersion == null) { + return false; + } + String[] parts = jmixVersion.split("\\."); + return parts.length > 2; + } + } diff --git a/deptool/src/main/java/io/jmix/dependency/cli/dependency/additional/AdditionalDependencyFileType.java b/deptool/src/main/java/io/jmix/dependency/cli/dependency/additional/AdditionalDependencyFileType.java new file mode 100644 index 0000000..7276ae9 --- /dev/null +++ b/deptool/src/main/java/io/jmix/dependency/cli/dependency/additional/AdditionalDependencyFileType.java @@ -0,0 +1,29 @@ +package io.jmix.dependency.cli.dependency.additional; + +import java.io.InputStream; + +public enum AdditionalDependencyFileType { + + PACKAGE_LOCK(AdditionalDependencyType.NPM, "package-lock.json"); + + private final String fileName; + + private final AdditionalDependencyType dependencyType; + + AdditionalDependencyFileType(AdditionalDependencyType dependencyType, String fileName) { + this.fileName = fileName; + this.dependencyType = dependencyType; + } + + public AdditionalDependencyType getDependencyType() { + return dependencyType; + } + + public String getFileName() { + return fileName; + } + + public InputStream findFileContent(String jmixVersion) { + return getDependencyType().findFileContent(jmixVersion, getFileName()); + } +} diff --git a/deptool/src/main/java/io/jmix/dependency/cli/dependency/additional/AdditionalDependencyType.java b/deptool/src/main/java/io/jmix/dependency/cli/dependency/additional/AdditionalDependencyType.java new file mode 100644 index 0000000..74d63f1 --- /dev/null +++ b/deptool/src/main/java/io/jmix/dependency/cli/dependency/additional/AdditionalDependencyType.java @@ -0,0 +1,68 @@ +package io.jmix.dependency.cli.dependency.additional; + +import java.io.InputStream; + +import static io.jmix.dependency.cli.dependency.JmixDependencies.*; + +public enum AdditionalDependencyType { + NPM("npm"); + + private final String directoryName; + + AdditionalDependencyType(String directoryName) { + this.directoryName = directoryName; + } + + public String getDirectoryName() { + return directoryName; + } + + InputStream findFileContent(String jmixVersion, String fileName) { + if (jmixVersion == null || jmixVersion.isBlank()) { + return null; + } + + if (hasPatch(jmixVersion)) { + return findFileForPatchVersion(jmixVersion, fileName); + } else { + return findFileForMinorVersion(jmixVersion, fileName); + } + } + + private InputStream findFileForMinorVersion(String jmixVersion, String fileName) { + String minorVersion = getMinorVersion(jmixVersion); + if (minorVersion == null || minorVersion.isBlank()) { + return null; + } + return findResourceAsStream(jmixVersion, fileName); + } + + private InputStream findFileForPatchVersion(String jmixVersion, String fileName) { + InputStream resource = null; + try { + int patch = Integer.parseInt(getPatchVersion(jmixVersion)); + for (int i = patch; i > 0; i--) { + if (resource != null) { + break; + } + resource = findResourceAsStream(jmixVersion, fileName); + } + } catch (NumberFormatException ignored) { + resource = findResourceAsStream(jmixVersion, fileName); + } + return resource; + } + + private InputStream findResourceAsStream(String jmixVersion, String fileName) { + return getClassLoader().getResourceAsStream(getFilePath(jmixVersion, fileName)); + } + + private String getFilePath(String jmixVersion, String fileName) { + return "jmix-dependencies/additional/%s/%s/%s" + .formatted(getDirectoryName(), jmixVersion, fileName); + } + + private ClassLoader getClassLoader() { + return getClass().getClassLoader(); + } +} diff --git a/deptool/src/main/resources/jmix-dependencies/additional-dependencies/version-2-5-0/package-lock.json b/deptool/src/main/resources/jmix-dependencies/additional/npm/2.5/package-lock.json similarity index 100% rename from deptool/src/main/resources/jmix-dependencies/additional-dependencies/version-2-5-0/package-lock.json rename to deptool/src/main/resources/jmix-dependencies/additional/npm/2.5/package-lock.json From 118871ec2d1f6fd20d63b5009ae590a4464fd5c6 Mon Sep 17 00:00:00 2001 From: Mikhail Fedoseev Date: Thu, 6 Mar 2025 15:35:25 +0400 Subject: [PATCH 05/10] Support for additional npm dependencies --- .../cli/command/ResolveNpmCommand.java | 1 + .../cli/dependency/JmixDependencies.java | 78 ++++++++++++++++++- .../additional/AdditionalDependencyType.java | 71 +++++++++++++++-- .../additional/npm/2.5/package-lock.json | 5 ++ 4 files changed, 149 insertions(+), 6 deletions(-) diff --git a/deptool/src/main/java/io/jmix/dependency/cli/command/ResolveNpmCommand.java b/deptool/src/main/java/io/jmix/dependency/cli/command/ResolveNpmCommand.java index fa33e49..8149a5d 100644 --- a/deptool/src/main/java/io/jmix/dependency/cli/command/ResolveNpmCommand.java +++ b/deptool/src/main/java/io/jmix/dependency/cli/command/ResolveNpmCommand.java @@ -174,6 +174,7 @@ private void resolveAdditionalDependencies() { try (InputStream packageLockContent = PACKAGE_LOCK.findFileContent(jmixVersion)) { if (packageLockContent == null) { + log.info("-= No additional dependencies was found, skipping this step =-"); return; } diff --git a/deptool/src/main/java/io/jmix/dependency/cli/dependency/JmixDependencies.java b/deptool/src/main/java/io/jmix/dependency/cli/dependency/JmixDependencies.java index bc3c39b..889d597 100644 --- a/deptool/src/main/java/io/jmix/dependency/cli/dependency/JmixDependencies.java +++ b/deptool/src/main/java/io/jmix/dependency/cli/dependency/JmixDependencies.java @@ -1,6 +1,8 @@ package io.jmix.dependency.cli.dependency; -import org.dom4j.*; +import org.dom4j.Document; +import org.dom4j.DocumentException; +import org.dom4j.Node; import org.dom4j.io.SAXReader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -8,6 +10,7 @@ import java.io.IOException; import java.io.InputStream; import java.util.*; +import java.util.regex.Pattern; import java.util.stream.Collectors; public class JmixDependencies { @@ -53,6 +56,10 @@ private static Set _getVersionSpecificDependencies(String version, boole } } + public static int compareVersions(String version1, String version2) { + return JmixVersionComparator.compareVersions(version1, version2); + } + /** * Extracts a minor version from version string. * Examples: @@ -119,4 +126,73 @@ public static boolean hasPatch(String jmixVersion) { return parts.length > 2; } + private static class JmixVersionComparator implements Comparator { + + private static final Pattern VERSION_SPLIT_REGEX = Pattern.compile("[.-]"); + + public static final JmixVersionComparator INSTANCE = new JmixVersionComparator(); + + public static int compareVersions(String v1, String v2) { + return INSTANCE.compare(v1, v2); + } + + /** +
    + *
  • null, null -> 0
  • + *
  • null, !null -> -1
  • + *
  • !null, null -> 1
  • + *
  • 2.0, 1.0 -> 1
  • + *
  • 1.0, 2.0 -> -1
  • + *
  • 2.0, 2.0 -> 0
  • + *
  • 2.0, 2.1 -> -1
  • + *
  • 2.0.1, 2.0.0 -> 1
  • + *
+ * @return >0 if v1 is newer than v2, 0 if equals, <0 if v1 is older than v2 + */ + @Override + public int compare(String v1, String v2) { + if (v1 == null && v2 != null) { + return -1; + } + + if (v2 == null && v1 != null) { + return 1; + } + + if (Objects.equals(v1, v2)) { + return 0; + } + + String[] strings1 = VERSION_SPLIT_REGEX.split(v1); + String[] strings2 = VERSION_SPLIT_REGEX.split(v2); + + for (int i = 0; i < strings1.length; i++) { + if (strings2.length <= i) { + return -1; + } + + String s1 = strings1[i]; + String s2 = strings2[i]; + + if (s1.equals(s2)) continue; + if (s1.equals("SNAPSHOT")) return 1; + if (s2.equals("SNAPSHOT")) return -1; + + try { + Integer n1 = Integer.valueOf(s1); + Integer n2 = Integer.valueOf(s2); + return n1 - n2; + } catch (NumberFormatException e) { + return s1.compareTo(s2); + } + } + + if (strings1.length < strings2.length) { + return 1; + } + + return 0; + } + } + } diff --git a/deptool/src/main/java/io/jmix/dependency/cli/dependency/additional/AdditionalDependencyType.java b/deptool/src/main/java/io/jmix/dependency/cli/dependency/additional/AdditionalDependencyType.java index 74d63f1..0f9231e 100644 --- a/deptool/src/main/java/io/jmix/dependency/cli/dependency/additional/AdditionalDependencyType.java +++ b/deptool/src/main/java/io/jmix/dependency/cli/dependency/additional/AdditionalDependencyType.java @@ -1,12 +1,23 @@ package io.jmix.dependency.cli.dependency.additional; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.filefilter.RegexFileFilter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; import java.io.InputStream; +import java.net.URL; +import java.nio.file.Paths; +import java.util.Collection; import static io.jmix.dependency.cli.dependency.JmixDependencies.*; public enum AdditionalDependencyType { NPM("npm"); + private static final String ADDITIONAL_DEPENDENCIES_RESOURCES_DIR = "jmix-dependencies/additional"; + private static final Logger log = LoggerFactory.getLogger(AdditionalDependencyType.class); private final String directoryName; AdditionalDependencyType(String directoryName) { @@ -25,7 +36,7 @@ InputStream findFileContent(String jmixVersion, String fileName) { if (hasPatch(jmixVersion)) { return findFileForPatchVersion(jmixVersion, fileName); } else { - return findFileForMinorVersion(jmixVersion, fileName); + return findFileForLatestVersion(jmixVersion, fileName); } } @@ -34,14 +45,22 @@ private InputStream findFileForMinorVersion(String jmixVersion, String fileName) if (minorVersion == null || minorVersion.isBlank()) { return null; } - return findResourceAsStream(jmixVersion, fileName); + return findResourceAsStream(minorVersion, fileName); + } + + private InputStream findFileForLatestVersion(String jmixVersion, String fileName) { + String latestVersion = getLatestVersion(jmixVersion); + if (latestVersion == null || latestVersion.isBlank()) { + return null; + } + return findResourceAsStream(latestVersion, fileName); } private InputStream findFileForPatchVersion(String jmixVersion, String fileName) { InputStream resource = null; try { int patch = Integer.parseInt(getPatchVersion(jmixVersion)); - for (int i = patch; i > 0; i--) { + for (int i = patch; i >= 0; i--) { if (resource != null) { break; } @@ -50,6 +69,11 @@ private InputStream findFileForPatchVersion(String jmixVersion, String fileName) } catch (NumberFormatException ignored) { resource = findResourceAsStream(jmixVersion, fileName); } + + if (resource == null) { + return findFileForMinorVersion(jmixVersion, fileName); + } + return resource; } @@ -58,8 +82,45 @@ private InputStream findResourceAsStream(String jmixVersion, String fileName) { } private String getFilePath(String jmixVersion, String fileName) { - return "jmix-dependencies/additional/%s/%s/%s" - .formatted(getDirectoryName(), jmixVersion, fileName); + return getResourceDir(jmixVersion) + "/" + fileName; + } + + private String getResourceDir(String jmixVersion) { + return getResourcesDir() + "/" + jmixVersion; + } + + private String getResourcesDir() { + return ADDITIONAL_DEPENDENCIES_RESOURCES_DIR + "/" + getDirectoryName(); + } + + private String getLatestVersion(String jmixVersion) { + try { + String minorVersion = getMinorVersion(jmixVersion); + if (minorVersion == null || minorVersion.isBlank()) { + return null; + } + + URL resourcesDirUrl = getClassLoader().getResource(getResourcesDir()); + if (resourcesDirUrl == null) { + return null; + } + + File resourcesDir = Paths.get(resourcesDirUrl.toURI()).toFile(); + Collection children = FileUtils.listFilesAndDirs(resourcesDir, + new RegexFileFilter("ignoreAll"), + new RegexFileFilter("[\\d.-]*")); + + File latestVersion = children.stream() + .filter(File::isDirectory) + .filter(dir -> dir.getName().startsWith(minorVersion)) + .min((f1, f2) -> compareVersions(f1.getName(), f2.getName())) + .orElse(null); + + return latestVersion == null ? null : latestVersion.getName(); + } catch (Exception e) { + log.warn("Can not find additional dependencies resources for latest version", e); + return null; + } } private ClassLoader getClassLoader() { diff --git a/deptool/src/main/resources/jmix-dependencies/additional/npm/2.5/package-lock.json b/deptool/src/main/resources/jmix-dependencies/additional/npm/2.5/package-lock.json index c135af3..a059f22 100644 --- a/deptool/src/main/resources/jmix-dependencies/additional/npm/2.5/package-lock.json +++ b/deptool/src/main/resources/jmix-dependencies/additional/npm/2.5/package-lock.json @@ -13,6 +13,11 @@ "path-to-regexp": "^6.3.0", "type-fest": "^4.26.1" } + }, + "node_modules/path-to-regexp": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", + "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==" } } } From 1ea65af93ae44efe9af3f5a41deee5151480eb15 Mon Sep 17 00:00:00 2001 From: Mikhail Fedoseev Date: Thu, 6 Mar 2025 16:41:43 +0400 Subject: [PATCH 06/10] Update package-lock.json --- .../additional/npm/2.5/package-lock.json | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/deptool/src/main/resources/jmix-dependencies/additional/npm/2.5/package-lock.json b/deptool/src/main/resources/jmix-dependencies/additional/npm/2.5/package-lock.json index a059f22..c22df32 100644 --- a/deptool/src/main/resources/jmix-dependencies/additional/npm/2.5/package-lock.json +++ b/deptool/src/main/resources/jmix-dependencies/additional/npm/2.5/package-lock.json @@ -14,10 +14,35 @@ "type-fest": "^4.26.1" } }, + "node_modules/@vaadin/vaadin-usage-statistics": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-usage-statistics/-/vaadin-usage-statistics-2.1.3.tgz", + "integrity": "sha512-8r4TNknD7OJQADe3VygeofFR7UNAXZ2/jjBFP5dgI8+2uMfnuGYgbuHivasKr9WSQ64sPej6m8rDoM1uSllXjQ==", + "hasInstallScript": true, + "dependencies": { + "@vaadin/vaadin-development-mode-detector": "^2.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/@vaadin/vaadin-development-mode-detector": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-development-mode-detector/-/vaadin-development-mode-detector-2.0.7.tgz", + "integrity": "sha512-9FhVhr0ynSR3X2ao+vaIEttcNU5XfzCbxtmYOV8uIRnUCtNgbvMOIcyGBvntsX9I5kvIP2dV3cFAOG9SILJzEA==" + }, "node_modules/path-to-regexp": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==" + }, + "node_modules/type-fest": { + "version": "4.37.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.37.0.tgz", + "integrity": "sha512-S/5/0kFftkq27FPNye0XM1e2NsnoD/3FS+pBmbjmmtLT6I+i344KoOf7pvXreaFsDamWeaJX55nczA1m5PsBDg==", + "engines": { + "node": ">=16" + } } } } From 5618f43d8783531a4a7b969f8382ededece07771 Mon Sep 17 00:00:00 2001 From: Mikhail Fedoseev Date: Thu, 6 Mar 2025 20:07:50 +0400 Subject: [PATCH 07/10] Update package-lock.json --- .../cli/command/ResolveJmixCommand.java | 5 + .../cli/command/ResolveNpmCommand.java | 49 ++-- .../cli/dependency/JmixDependencies.java | 147 +---------- .../AdditionalDependencyFileType.java | 4 +- .../additional/AdditionalDependencyType.java | 107 ++------ .../cli/gradle/JmixGradleClient.java | 3 +- .../jmix/dependency/cli/util/StringUtils.java | 12 + .../dependency/cli/version/JmixVersion.java | 61 +++++ .../cli/version/JmixVersionComparator.java | 70 ++++++ .../cli/version/JmixVersionUtils.java | 231 ++++++++++++++++++ .../npm/{2.5 => 2.5.0}/package-lock.json | 0 11 files changed, 440 insertions(+), 249 deletions(-) create mode 100644 deptool/src/main/java/io/jmix/dependency/cli/util/StringUtils.java create mode 100644 deptool/src/main/java/io/jmix/dependency/cli/version/JmixVersion.java create mode 100644 deptool/src/main/java/io/jmix/dependency/cli/version/JmixVersionComparator.java create mode 100644 deptool/src/main/java/io/jmix/dependency/cli/version/JmixVersionUtils.java rename deptool/src/main/resources/jmix-dependencies/additional/npm/{2.5 => 2.5.0}/package-lock.json (100%) diff --git a/deptool/src/main/java/io/jmix/dependency/cli/command/ResolveJmixCommand.java b/deptool/src/main/java/io/jmix/dependency/cli/command/ResolveJmixCommand.java index 8f0e6b3..0c9db8d 100644 --- a/deptool/src/main/java/io/jmix/dependency/cli/command/ResolveJmixCommand.java +++ b/deptool/src/main/java/io/jmix/dependency/cli/command/ResolveJmixCommand.java @@ -4,6 +4,7 @@ import com.beust.jcommander.Parameters; import io.jmix.dependency.cli.dependency.JmixDependencies; import io.jmix.dependency.cli.gradle.JmixGradleClient; +import io.jmix.dependency.cli.version.JmixVersion; import org.gradle.tooling.ProjectConnection; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -51,8 +52,12 @@ public class ResolveJmixCommand implements BaseCommand { "If credentials are not required then just an URL must be passed", order = 9) private List repositories; + private JmixVersion parsedVersion; + @Override public void run() { + parsedVersion = JmixVersion.from(jmixVersion); + if (jmixPluginVersion == null) { jmixPluginVersion = jmixVersion; } diff --git a/deptool/src/main/java/io/jmix/dependency/cli/command/ResolveNpmCommand.java b/deptool/src/main/java/io/jmix/dependency/cli/command/ResolveNpmCommand.java index 8149a5d..7ca35f6 100644 --- a/deptool/src/main/java/io/jmix/dependency/cli/command/ResolveNpmCommand.java +++ b/deptool/src/main/java/io/jmix/dependency/cli/command/ResolveNpmCommand.java @@ -4,6 +4,7 @@ import com.beust.jcommander.Parameters; import io.jmix.dependency.cli.dependency.JmixDependencies; import io.jmix.dependency.cli.gradle.JmixGradleClient; +import io.jmix.dependency.cli.version.JmixVersion; import org.apache.commons.io.FileUtils; import org.gradle.tooling.ProjectConnection; import org.slf4j.Logger; @@ -57,8 +58,12 @@ public class ResolveNpmCommand implements BaseCommand { "If credentials are not required then just an URL must be passed", order = 9) private List repositories; + private JmixVersion parsedVersion; + @Override public void run() { + parsedVersion = JmixVersion.from(jmixVersion); + if (jmixPluginVersion == null) { jmixPluginVersion = jmixVersion; } @@ -159,10 +164,6 @@ protected void resolveDependencies(JmixGradleClient jmixGradleClient) { } private void resolveAdditionalDependencies() { - if (jmixVersion == null) { - return; - } - try { File additionalDependenciesDir = Paths.get(resolverProjectPath, "additional-dependencies").toAbsolutePath().normalize().toFile(); @@ -172,27 +173,33 @@ private void resolveAdditionalDependencies() { return; } - try (InputStream packageLockContent = PACKAGE_LOCK.findFileContent(jmixVersion)) { - if (packageLockContent == null) { - log.info("-= No additional dependencies was found, skipping this step =-"); - return; - } + resolveAdditionalPackageLockFile(additionalDependenciesDir); + + } catch (Exception e) { + log.info("Error when trying to download additional dependencies", e); + } + } - log.info("-= Resolve additional dependencies =-"); + private void resolveAdditionalPackageLockFile(File additionalDependenciesDir) throws IOException { + String packageLockFileName = PACKAGE_LOCK.getFileName(); - try { - File packageLockJson = new File(additionalDependenciesDir, "package-lock.json"); - //noinspection ResultOfMethodCallIgnored - packageLockJson.createNewFile(); - log.info("-= Copy additional dependencies package-lock.json =-"); - FileUtils.copyInputStreamToFile(packageLockContent, packageLockJson); - } catch (IOException e) { - throw new RuntimeException("Unable to copy additional dependencies package-lock.json", e); - } + try (InputStream packageLockContent = PACKAGE_LOCK.findFileContent(parsedVersion)) { + if (packageLockContent == null) { + log.info("-= No additional dependencies was found, skipping this step =-"); + return; } - } catch (Exception e) { - log.info("Error when trying to download additional dependencies", e); + log.info("-= Resolve additional dependencies =-"); + + try { + File packageLockJson = new File(additionalDependenciesDir, packageLockFileName); + //noinspection ResultOfMethodCallIgnored + packageLockJson.createNewFile(); + log.info("-= Copy additional dependencies files =-"); + FileUtils.copyInputStreamToFile(packageLockContent, packageLockJson); + } catch (IOException e) { + throw new RuntimeException("Unable to copy additional dependencies file: " + packageLockFileName, e); + } } } diff --git a/deptool/src/main/java/io/jmix/dependency/cli/dependency/JmixDependencies.java b/deptool/src/main/java/io/jmix/dependency/cli/dependency/JmixDependencies.java index 889d597..beb95b0 100644 --- a/deptool/src/main/java/io/jmix/dependency/cli/dependency/JmixDependencies.java +++ b/deptool/src/main/java/io/jmix/dependency/cli/dependency/JmixDependencies.java @@ -1,5 +1,6 @@ package io.jmix.dependency.cli.dependency; +import io.jmix.dependency.cli.version.JmixVersionUtils; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Node; @@ -9,8 +10,9 @@ import java.io.IOException; import java.io.InputStream; -import java.util.*; -import java.util.regex.Pattern; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import java.util.stream.Collectors; public class JmixDependencies { @@ -18,7 +20,7 @@ public class JmixDependencies { private static final Logger log = LoggerFactory.getLogger(JmixDependencies.class); public static Set getVersionSpecificJmixDependencies(String jmixVersion, boolean resolveCommercialAddons) { - String minorJmixVersion = getMinorVersion(jmixVersion); + String minorJmixVersion = JmixVersionUtils.getMinorVersion(jmixVersion); Set dependencies = _getVersionSpecificDependencies(minorJmixVersion, resolveCommercialAddons); dependencies.addAll(_getVersionSpecificDependencies(jmixVersion, resolveCommercialAddons)); //if there are no files for the given dependency version then use the default file (dependencies-default.xml) @@ -56,143 +58,4 @@ private static Set _getVersionSpecificDependencies(String version, boole } } - public static int compareVersions(String version1, String version2) { - return JmixVersionComparator.compareVersions(version1, version2); - } - - /** - * Extracts a minor version from version string. - * Examples: - *
    - *
  • null -> null
  • - *
  • "" -> ""
  • - *
  • abc -> ""
  • - *
  • 1.4.2 -> 1.4
  • - *
  • 1.4 -> 1.4
  • - *
  • 1 -> 1.0
  • - *
- */ - public static String getMinorVersion(String jmixVersion) { - if (jmixVersion == null) { - return null; - } - - String[] parts = jmixVersion.split("\\."); - if (parts.length < 2) { - if (parts.length == 0) { - return ""; - } else { - return parts[0] + "." + 0; - } - } - - return parts[0] + "." + parts[1]; - } - - /** - * Extracts a patch from version string. - * Examples: - *
    - *
  • null -> null
  • - *
  • "" -> ""
  • - *
  • abc -> ""
  • - *
  • 1.4.2 -> 2
  • - *
  • 1.4 -> 0
  • - *
  • 1 -> 0
  • - *
- */ - public static String getPatchVersion(String jmixVersion) { - if (jmixVersion == null) { - return null; - } - - String[] parts = jmixVersion.split("\\."); - if (parts.length < 3) { - if (parts.length == 0) { - return ""; - } else { - return "0"; - } - } - - return parts[2]; - } - - public static boolean hasPatch(String jmixVersion) { - if (jmixVersion == null) { - return false; - } - String[] parts = jmixVersion.split("\\."); - return parts.length > 2; - } - - private static class JmixVersionComparator implements Comparator { - - private static final Pattern VERSION_SPLIT_REGEX = Pattern.compile("[.-]"); - - public static final JmixVersionComparator INSTANCE = new JmixVersionComparator(); - - public static int compareVersions(String v1, String v2) { - return INSTANCE.compare(v1, v2); - } - - /** -
    - *
  • null, null -> 0
  • - *
  • null, !null -> -1
  • - *
  • !null, null -> 1
  • - *
  • 2.0, 1.0 -> 1
  • - *
  • 1.0, 2.0 -> -1
  • - *
  • 2.0, 2.0 -> 0
  • - *
  • 2.0, 2.1 -> -1
  • - *
  • 2.0.1, 2.0.0 -> 1
  • - *
- * @return >0 if v1 is newer than v2, 0 if equals, <0 if v1 is older than v2 - */ - @Override - public int compare(String v1, String v2) { - if (v1 == null && v2 != null) { - return -1; - } - - if (v2 == null && v1 != null) { - return 1; - } - - if (Objects.equals(v1, v2)) { - return 0; - } - - String[] strings1 = VERSION_SPLIT_REGEX.split(v1); - String[] strings2 = VERSION_SPLIT_REGEX.split(v2); - - for (int i = 0; i < strings1.length; i++) { - if (strings2.length <= i) { - return -1; - } - - String s1 = strings1[i]; - String s2 = strings2[i]; - - if (s1.equals(s2)) continue; - if (s1.equals("SNAPSHOT")) return 1; - if (s2.equals("SNAPSHOT")) return -1; - - try { - Integer n1 = Integer.valueOf(s1); - Integer n2 = Integer.valueOf(s2); - return n1 - n2; - } catch (NumberFormatException e) { - return s1.compareTo(s2); - } - } - - if (strings1.length < strings2.length) { - return 1; - } - - return 0; - } - } - } diff --git a/deptool/src/main/java/io/jmix/dependency/cli/dependency/additional/AdditionalDependencyFileType.java b/deptool/src/main/java/io/jmix/dependency/cli/dependency/additional/AdditionalDependencyFileType.java index 7276ae9..fdd7261 100644 --- a/deptool/src/main/java/io/jmix/dependency/cli/dependency/additional/AdditionalDependencyFileType.java +++ b/deptool/src/main/java/io/jmix/dependency/cli/dependency/additional/AdditionalDependencyFileType.java @@ -1,5 +1,7 @@ package io.jmix.dependency.cli.dependency.additional; +import io.jmix.dependency.cli.version.JmixVersion; + import java.io.InputStream; public enum AdditionalDependencyFileType { @@ -23,7 +25,7 @@ public String getFileName() { return fileName; } - public InputStream findFileContent(String jmixVersion) { + public InputStream findFileContent(JmixVersion jmixVersion) { return getDependencyType().findFileContent(jmixVersion, getFileName()); } } diff --git a/deptool/src/main/java/io/jmix/dependency/cli/dependency/additional/AdditionalDependencyType.java b/deptool/src/main/java/io/jmix/dependency/cli/dependency/additional/AdditionalDependencyType.java index 0f9231e..4c02eb5 100644 --- a/deptool/src/main/java/io/jmix/dependency/cli/dependency/additional/AdditionalDependencyType.java +++ b/deptool/src/main/java/io/jmix/dependency/cli/dependency/additional/AdditionalDependencyType.java @@ -1,23 +1,13 @@ package io.jmix.dependency.cli.dependency.additional; -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.filefilter.RegexFileFilter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import io.jmix.dependency.cli.version.JmixVersion; -import java.io.File; import java.io.InputStream; -import java.net.URL; -import java.nio.file.Paths; -import java.util.Collection; - -import static io.jmix.dependency.cli.dependency.JmixDependencies.*; public enum AdditionalDependencyType { NPM("npm"); private static final String ADDITIONAL_DEPENDENCIES_RESOURCES_DIR = "jmix-dependencies/additional"; - private static final Logger log = LoggerFactory.getLogger(AdditionalDependencyType.class); private final String directoryName; AdditionalDependencyType(String directoryName) { @@ -28,101 +18,50 @@ public String getDirectoryName() { return directoryName; } - InputStream findFileContent(String jmixVersion, String fileName) { - if (jmixVersion == null || jmixVersion.isBlank()) { - return null; - } - - if (hasPatch(jmixVersion)) { - return findFileForPatchVersion(jmixVersion, fileName); - } else { - return findFileForLatestVersion(jmixVersion, fileName); - } - } - - private InputStream findFileForMinorVersion(String jmixVersion, String fileName) { - String minorVersion = getMinorVersion(jmixVersion); - if (minorVersion == null || minorVersion.isBlank()) { - return null; - } - return findResourceAsStream(minorVersion, fileName); - } - - private InputStream findFileForLatestVersion(String jmixVersion, String fileName) { - String latestVersion = getLatestVersion(jmixVersion); - if (latestVersion == null || latestVersion.isBlank()) { - return null; - } - return findResourceAsStream(latestVersion, fileName); - } - - private InputStream findFileForPatchVersion(String jmixVersion, String fileName) { + InputStream findFileContent(JmixVersion jmixVersion, String fileName) { InputStream resource = null; try { - int patch = Integer.parseInt(getPatchVersion(jmixVersion)); - for (int i = patch; i >= 0; i--) { - if (resource != null) { - break; + if (!jmixVersion.isStable()) { + for (int patch = 0; patch <= jmixVersion.patch(); patch++) { + if (resource != null) { + break; + } + String versionString = jmixVersion.withPatch(patch).versionString(false); + resource = findResourceAsStream(versionString, fileName); + } + } else { + for (int patch = jmixVersion.patch(); patch >= 0; patch--) { + if (resource != null) { + break; + } + String versionString = jmixVersion.withPatch(patch).versionString(false); + resource = findResourceAsStream(versionString, fileName); } - resource = findResourceAsStream(jmixVersion, fileName); } } catch (NumberFormatException ignored) { - resource = findResourceAsStream(jmixVersion, fileName); - } - - if (resource == null) { - return findFileForMinorVersion(jmixVersion, fileName); + resource = findResourceAsStream(jmixVersion.versionString(false), fileName); } return resource; } + private InputStream findResourceAsStream(String jmixVersion, String fileName) { return getClassLoader().getResourceAsStream(getFilePath(jmixVersion, fileName)); } private String getFilePath(String jmixVersion, String fileName) { - return getResourceDir(jmixVersion) + "/" + fileName; + return getResourcesDir(jmixVersion) + "/" + fileName; } - private String getResourceDir(String jmixVersion) { - return getResourcesDir() + "/" + jmixVersion; + private String getResourcesDir(String jmixVersion) { + return getVersionsDir() + "/" + jmixVersion; } - private String getResourcesDir() { + private String getVersionsDir() { return ADDITIONAL_DEPENDENCIES_RESOURCES_DIR + "/" + getDirectoryName(); } - private String getLatestVersion(String jmixVersion) { - try { - String minorVersion = getMinorVersion(jmixVersion); - if (minorVersion == null || minorVersion.isBlank()) { - return null; - } - - URL resourcesDirUrl = getClassLoader().getResource(getResourcesDir()); - if (resourcesDirUrl == null) { - return null; - } - - File resourcesDir = Paths.get(resourcesDirUrl.toURI()).toFile(); - Collection children = FileUtils.listFilesAndDirs(resourcesDir, - new RegexFileFilter("ignoreAll"), - new RegexFileFilter("[\\d.-]*")); - - File latestVersion = children.stream() - .filter(File::isDirectory) - .filter(dir -> dir.getName().startsWith(minorVersion)) - .min((f1, f2) -> compareVersions(f1.getName(), f2.getName())) - .orElse(null); - - return latestVersion == null ? null : latestVersion.getName(); - } catch (Exception e) { - log.warn("Can not find additional dependencies resources for latest version", e); - return null; - } - } - private ClassLoader getClassLoader() { return getClass().getClassLoader(); } diff --git a/deptool/src/main/java/io/jmix/dependency/cli/gradle/JmixGradleClient.java b/deptool/src/main/java/io/jmix/dependency/cli/gradle/JmixGradleClient.java index f035f1f..b0e3ba8 100644 --- a/deptool/src/main/java/io/jmix/dependency/cli/gradle/JmixGradleClient.java +++ b/deptool/src/main/java/io/jmix/dependency/cli/gradle/JmixGradleClient.java @@ -1,5 +1,6 @@ package io.jmix.dependency.cli.gradle; +import io.jmix.dependency.cli.util.StringUtils; import org.gradle.tooling.GradleConnector; import org.gradle.tooling.ProjectConnection; @@ -26,7 +27,7 @@ public JmixGradleClient(String projectDir, String gradleUserHomeDir, String grad public ProjectConnection getProjectConnection() { GradleConnector gradleConnector = GradleConnector.newConnector().forProjectDirectory(new File(projectDir)); - if (gradleVersion != null && !gradleVersion.isBlank()) { + if (StringUtils.isBlank(gradleVersion)) { gradleConnector.useGradleVersion(gradleVersion); } diff --git a/deptool/src/main/java/io/jmix/dependency/cli/util/StringUtils.java b/deptool/src/main/java/io/jmix/dependency/cli/util/StringUtils.java new file mode 100644 index 0000000..9beb668 --- /dev/null +++ b/deptool/src/main/java/io/jmix/dependency/cli/util/StringUtils.java @@ -0,0 +1,12 @@ +package io.jmix.dependency.cli.util; + +public final class StringUtils { + + public static boolean isBlank(String str) { + return str == null || str.isBlank(); + } + + public static boolean isNotBlank(String str) { + return !isBlank(str); + } +} diff --git a/deptool/src/main/java/io/jmix/dependency/cli/version/JmixVersion.java b/deptool/src/main/java/io/jmix/dependency/cli/version/JmixVersion.java new file mode 100644 index 0000000..4dee7e8 --- /dev/null +++ b/deptool/src/main/java/io/jmix/dependency/cli/version/JmixVersion.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2008-2022 Haulmont. All rights reserved. + * Use is subject to license terms, see http://www.cuba-platform.com/commercial-software-license for details. + */ + +package io.jmix.dependency.cli.version; + +public record JmixVersion(int major, int minor, int patch, String suffix) { + + private static final Character DOT = '.'; + + public static JmixVersion from(String versionString) { + return JmixVersionUtils.toJmixVersion(versionString); + } + + public JmixVersion withMajor(int major) { + return new JmixVersion(major, minor, patch, suffix); + } + + public JmixVersion withMinor(int minor) { + return new JmixVersion(major, minor, patch, suffix); + } + + public JmixVersion withPatch(int patch) { + return new JmixVersion(major, minor, patch, suffix); + } + + public boolean isSnapshot() { + return JmixVersionUtils.isSnapshot(versionString()); + } + + public boolean isStable() { + return JmixVersionUtils.isStable(versionString()); + } + + public String versionString() { + return versionString(true); + } + + public String versionString(boolean withSuffix) { + StringBuilder versionBuilder = new StringBuilder() + .append(major).append(DOT) + .append(minor).append(DOT) + .append(patch); + + if (withSuffix) { + versionBuilder.append(suffix); + } + + return versionBuilder.toString(); + } + + public JmixVersion copy() { + return JmixVersion.from(versionString()); + } + + @Override + public String toString() { + return versionString(); + } +} diff --git a/deptool/src/main/java/io/jmix/dependency/cli/version/JmixVersionComparator.java b/deptool/src/main/java/io/jmix/dependency/cli/version/JmixVersionComparator.java new file mode 100644 index 0000000..03c3b94 --- /dev/null +++ b/deptool/src/main/java/io/jmix/dependency/cli/version/JmixVersionComparator.java @@ -0,0 +1,70 @@ +package io.jmix.dependency.cli.version; + +import java.util.Comparator; +import java.util.Objects; +import java.util.regex.Pattern; + +public class JmixVersionComparator implements Comparator { + + private static final Pattern VERSION_SPLIT_REGEX = Pattern.compile("[.-]"); + + public static final JmixVersionComparator INSTANCE = new JmixVersionComparator(); + + /** + *
    + *
  • null, null -> 0
  • + *
  • null, !null -> -1
  • + *
  • !null, null -> 1
  • + *
  • 2.0, 1.0 -> 1
  • + *
  • 1.0, 2.0 -> -1
  • + *
  • 2.0, 2.0 -> 0
  • + *
  • 2.0, 2.1 -> -1
  • + *
  • 2.0.1, 2.0.0 -> 1
  • + *
  • 2.0, 2.0.1 -> -1
  • + *
+ * + * @return >0 if v1 is newer than v2, 0 if equals, <0 if v1 is older than v2 + */ + @Override + public int compare(String v1, String v2) { + if (v1 == null && v2 != null) { + return -1; + } + + if (v2 == null && v1 != null) { + return 1; + } + + if (Objects.equals(v1, v2)) { + return 0; + } + + String[] strings1 = VERSION_SPLIT_REGEX.split(v1); + String[] strings2 = VERSION_SPLIT_REGEX.split(v2); + + for (int i = 0; i < strings1.length; i++) { + if (strings2.length <= i) { + return 1; + } + + String s1 = strings1[i]; + String s2 = strings2[i]; + + if (s1.equals(s2)) continue; + + try { + Integer n1 = Integer.valueOf(s1); + Integer n2 = Integer.valueOf(s2); + return n1 - n2; + } catch (NumberFormatException e) { + return s1.compareTo(s2); + } + } + + if (strings1.length < strings2.length) { + return -1; + } + + return 0; + } +} \ No newline at end of file diff --git a/deptool/src/main/java/io/jmix/dependency/cli/version/JmixVersionUtils.java b/deptool/src/main/java/io/jmix/dependency/cli/version/JmixVersionUtils.java new file mode 100644 index 0000000..a099ab5 --- /dev/null +++ b/deptool/src/main/java/io/jmix/dependency/cli/version/JmixVersionUtils.java @@ -0,0 +1,231 @@ +package io.jmix.dependency.cli.version; + +import io.jmix.dependency.cli.util.StringUtils; + +import java.util.List; +import java.util.regex.Pattern; + +public class JmixVersionUtils { + + private static final Pattern VERSION_SPLIT_REGEX = Pattern.compile("[.-]"); + private static final Pattern UNSTABLE_VERSION_PATTERN = Pattern.compile("(-\\w*$)|(\\.[a-zA-Z]+\\d*$)"); + private static final Pattern SNAPSHOT_PATTERN = Pattern.compile("-SNAPSHOT$"); + private static final Pattern RC_PATTERN = Pattern.compile("-RC$"); + + public static final JmixVersionComparator VERSION_COMPARATOR = JmixVersionComparator.INSTANCE; + + public static JmixVersion toJmixVersion(String version) { + IllegalArgumentException invalidVersionException = + new IllegalArgumentException("Invalid Jmix version. Version should be in format x.y.z"); + + if (!isValidVersion(version)) { + throw invalidVersionException; + } + + Integer major = extractMajorNumber(version); + Integer minor = extractMinorNumber(version); + Integer patch = extractPatchNumber(version); + + if (major == null || minor == null || patch == null) { + throw invalidVersionException; + } + + String suffixSeparator = "-"; + String suffix = extractSuffix(version, suffixSeparator); + if (StringUtils.isNotBlank(suffix)) { + suffix = suffixSeparator + suffix; + } + + return new JmixVersion(major, minor, patch, suffix); + } + + /** + * @return true if {@code version} has major, minor and patch parts. + */ + public static boolean isValidVersion(String version) { + return hasPatch(version); + } + + public static boolean hasPatch(String version) { + if (StringUtils.isBlank(version)) { + return false; + } + return VERSION_SPLIT_REGEX.split(version).length > 2; + } + + public static int compare(String v1, String v2) { + return VERSION_COMPARATOR.compare(v1, v2); + } + + /** + * Extracts a minor version from version string. + * Examples: + *
    + *
  • null -> null
  • + *
  • "" -> ""
  • + *
  • abc -> ""
  • + *
  • 1.4.2 -> 1.4
  • + *
  • 1.4 -> 1.4
  • + *
  • 1 -> 1.0
  • + *
+ */ + public static String getMinorVersion(String version) { + if (version == null) { + return null; + } + + String[] parts = version.split("\\."); + if (parts.length < 2) { + if (parts.length == 0) { + return ""; + } else { + return parts[0] + "." + 0; + } + } + + return parts[0] + "." + parts[1]; + } + + public static Integer extractMajorNumber(String version) { + String major = getVersionPartByIndex(version, 0); + return parseNumberSafely(major); + } + + /** + * Extracts a minor number from version string. + *
    + *
  • null -> null
  • + *
  • "" -> null
  • + *
  • abc -> null
  • + *
  • 1.4.2 -> 4
  • + *
  • 1.4 -> 4
  • + *
  • 1 -> 0
  • + *
+ */ + public static Integer extractMinorNumber(String version) { + if (StringUtils.isBlank(version)) { + return null; + } + + String[] parts = VERSION_SPLIT_REGEX.split(version); + if (parts.length < 2) { + if (parts.length == 0) { + return null; + } else { + return 0; + } + } + + String minor = getVersionPartByIndex(version, 1); + return parseNumberSafely(minor); + } + + /** + * Extracts a patch number from version string. + *
    + *
  • null -> null
  • + *
  • "" -> null
  • + *
  • abc -> null
  • + *
  • 1.4.2 -> 2
  • + *
  • 1.4 -> 0
  • + *
  • 1 -> 0
  • + *
+ */ + public static Integer extractPatchNumber(String version) { + String[] parts = VERSION_SPLIT_REGEX.split(version); + if (parts.length < 3) { + if (parts.length == 0) { + return null; + } else { + return 0; + } + } + + String patch = getVersionPartByIndex(version, 2); + return parseNumberSafely(patch); + } + + public static String extractSuffix(String version, String separator) { + if (StringUtils.isBlank(version)) { + return ""; + } + + String[] split = version.split(separator); + if (split.length < 2) { + return ""; + } + + return split[1]; + } + + public static boolean isSnapshot(String version) { + return StringUtils.isNotBlank(version) && SNAPSHOT_PATTERN.matcher(version).find(); + } + + public static boolean isRC(String version) { + return StringUtils.isNotBlank(version) && RC_PATTERN.matcher(version).find(); + } + + public static boolean isUnstable(String version) { + return StringUtils.isNotBlank(version) && UNSTABLE_VERSION_PATTERN.matcher(version).find(); + } + + public static boolean isStable(String version) { + return !isUnstable(version); + } + + /** + *

Returns version without RC or SNAPSHOT suffix

+ * + *
+     * null           -> null
+     * ""             -> null
+     * " "            -> null
+     * "bob"          -> "bob"
+     * "7.0-SNAPSHOT" -> "7.0"
+     * "7.0.0.BETA1"  -> "7.0.0"
+     * 
+ */ + public static String getStableVersion(String version) { + return StringUtils.isBlank(version) ? null : UNSTABLE_VERSION_PATTERN.matcher(version).replaceAll(""); + } + + public static void sort(List versions) { + versions.sort((v1, v2) -> -VERSION_COMPARATOR.compare(v1, v2)); + } + + /** + *
    + *
  • null, _ -> null
  • + *
  • "", _ -> null
  • + *
  • abc, _ -> null
  • + * + *
  • 1.4.0, 0 -> 1
  • + *
  • 1.4.0, 1 -> 4
  • + *
  • 1.4.0, 2 -> 0
  • + *
  • 1.4.0, 3 -> null
  • + *
+ */ + private static String getVersionPartByIndex(String version, int partIndex) { + if (StringUtils.isBlank(version)) { + return null; + } + + String[] parts = VERSION_SPLIT_REGEX.split(version); + if (parts.length >= partIndex + 1) { + return parts[partIndex]; + } else { + return null; + } + } + + private static Integer parseNumberSafely(String number) { + if (number != null) { + try { + return Integer.parseInt(number); + } catch (Exception ignored) { + } + } + return null; + } +} diff --git a/deptool/src/main/resources/jmix-dependencies/additional/npm/2.5/package-lock.json b/deptool/src/main/resources/jmix-dependencies/additional/npm/2.5.0/package-lock.json similarity index 100% rename from deptool/src/main/resources/jmix-dependencies/additional/npm/2.5/package-lock.json rename to deptool/src/main/resources/jmix-dependencies/additional/npm/2.5.0/package-lock.json From d900223afa143e35003c813692874797288bf04f Mon Sep 17 00:00:00 2001 From: Mikhail Fedoseev Date: Thu, 6 Mar 2025 23:06:10 +0400 Subject: [PATCH 08/10] Add tests --- .../dependency/cli/version/JmixVersion.java | 11 ++- .../cli/version/JmixVersionComparator.java | 2 +- .../test/AdditionalDependenciesTest.java | 33 +++++++++ .../io/jmix/deptool/test/JmixVersionTest.java | 69 +++++++++++++++++++ 4 files changed, 113 insertions(+), 2 deletions(-) create mode 100644 deptool/src/test/java/io/jmix/deptool/test/AdditionalDependenciesTest.java create mode 100644 deptool/src/test/java/io/jmix/deptool/test/JmixVersionTest.java diff --git a/deptool/src/main/java/io/jmix/dependency/cli/version/JmixVersion.java b/deptool/src/main/java/io/jmix/dependency/cli/version/JmixVersion.java index 4dee7e8..af81735 100644 --- a/deptool/src/main/java/io/jmix/dependency/cli/version/JmixVersion.java +++ b/deptool/src/main/java/io/jmix/dependency/cli/version/JmixVersion.java @@ -5,7 +5,7 @@ package io.jmix.dependency.cli.version; -public record JmixVersion(int major, int minor, int patch, String suffix) { +public record JmixVersion(int major, int minor, int patch, String suffix) implements Comparable { private static final Character DOT = '.'; @@ -29,6 +29,10 @@ public boolean isSnapshot() { return JmixVersionUtils.isSnapshot(versionString()); } + public boolean isRC() { + return JmixVersionUtils.isRC(versionString()); + } + public boolean isStable() { return JmixVersionUtils.isStable(versionString()); } @@ -58,4 +62,9 @@ public JmixVersion copy() { public String toString() { return versionString(); } + + @Override + public int compareTo(JmixVersion o) { + return JmixVersionUtils.compare(versionString(), o.versionString()); + } } diff --git a/deptool/src/main/java/io/jmix/dependency/cli/version/JmixVersionComparator.java b/deptool/src/main/java/io/jmix/dependency/cli/version/JmixVersionComparator.java index 03c3b94..ace8af4 100644 --- a/deptool/src/main/java/io/jmix/dependency/cli/version/JmixVersionComparator.java +++ b/deptool/src/main/java/io/jmix/dependency/cli/version/JmixVersionComparator.java @@ -31,7 +31,7 @@ public int compare(String v1, String v2) { return -1; } - if (v2 == null && v1 != null) { + if (v1 != null && v2 == null) { return 1; } diff --git a/deptool/src/test/java/io/jmix/deptool/test/AdditionalDependenciesTest.java b/deptool/src/test/java/io/jmix/deptool/test/AdditionalDependenciesTest.java new file mode 100644 index 0000000..05107c8 --- /dev/null +++ b/deptool/src/test/java/io/jmix/deptool/test/AdditionalDependenciesTest.java @@ -0,0 +1,33 @@ +package io.jmix.deptool.test; + +import io.jmix.dependency.cli.version.JmixVersion; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +import static io.jmix.dependency.cli.dependency.additional.AdditionalDependencyFileType.PACKAGE_LOCK; + +public class AdditionalDependenciesTest { + + @Test + public void testNpmDependencies() throws IOException { + JmixVersion jmixVersion = JmixVersion.from("2.5.0"); + try (var fileContent = PACKAGE_LOCK.findFileContent(jmixVersion)) { + byte[] package_lock_jmix_2_5 = fileContent.readAllBytes(); + Assertions.assertNotNull(package_lock_jmix_2_5); + testPackageJson(jmixVersion.withPatch(5), package_lock_jmix_2_5, true); + Assertions.assertThrows(NullPointerException.class, () -> { + testPackageJson(jmixVersion.withMajor(1), package_lock_jmix_2_5, false); + }); + } + } + + private void testPackageJson(JmixVersion jmixVersion, byte[] expected, boolean shouldBeEquals) throws IOException { + try (var content = PACKAGE_LOCK.findFileContent(jmixVersion)) { + byte[] actual = content.readAllBytes(); + Assertions.assertNotNull(actual); + Assertions.assertArrayEquals(expected, actual); + } + } +} diff --git a/deptool/src/test/java/io/jmix/deptool/test/JmixVersionTest.java b/deptool/src/test/java/io/jmix/deptool/test/JmixVersionTest.java new file mode 100644 index 0000000..98f7e5f --- /dev/null +++ b/deptool/src/test/java/io/jmix/deptool/test/JmixVersionTest.java @@ -0,0 +1,69 @@ +package io.jmix.deptool.test; + +import io.jmix.dependency.cli.version.JmixVersion; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.function.Function; + +import static org.junit.jupiter.api.Assertions.*; + +public class JmixVersionTest { + + @Test + public void testVersionParsing() { + String snapshotVersion = "2.5.999-SNAPSHOT"; + String rcVersion = "2.5.0-RC"; + String releaseVersion = "2.5.0"; + + var supportedVersions = List.of( + "1.5.0", + releaseVersion, + "2.5.0.1", + snapshotVersion, + rcVersion, + "2.5.0.1-RC", + "2.5.0-RC2" + ); + assertDoesNotThrow(() -> supportedVersions.forEach(JmixVersion::from)); + + JmixVersion snapshot = JmixVersion.from(snapshotVersion); + assertEquals(snapshotVersion, snapshot.versionString()); + assertEquals("2.5.999", snapshot.versionString(false)); + assertNotEquals(snapshotVersion, snapshot.versionString(false)); + assertTrue(snapshot.isSnapshot() && !snapshot.isStable() && !snapshot.isRC()); + + JmixVersion rc = JmixVersion.from(rcVersion); + assertEquals(rcVersion, rc.versionString()); + assertEquals("2.5.0", rc.versionString(false)); + assertNotEquals(rcVersion, rc.versionString(false)); + assertTrue(rc.isRC() && !rc.isStable() && !rc.isSnapshot()); + + JmixVersion release = JmixVersion.from(releaseVersion); + assertEquals(releaseVersion, release.versionString()); + assertEquals(releaseVersion, release.versionString(false)); + assertTrue(release.isStable() && !release.isSnapshot() && !release.isSnapshot()); + + var unsupportedVersions = List.of( + "abc", + "a.b.c", + "1-2-3", + "1.2.3b", + "1.2.3.", + "2.5" + ); + assertThrows(Throwable.class, () -> unsupportedVersions.forEach(JmixVersion::from)); + } + + @Test + public void testVersionComparing() { + JmixVersion fixedVersion = JmixVersion.from("1.5.0"); + Function compareVersions = jmixVersion -> jmixVersion.compareTo(fixedVersion); + + JmixVersion dynamicVersion = JmixVersion.from("2.5.0"); + + assertTrue(compareVersions.apply(dynamicVersion) > 0); + assertTrue(compareVersions.apply(dynamicVersion.withMajor(1).withMinor(4)) < 0); + assertEquals(0, compareVersions.apply(dynamicVersion.withMajor(1))); + } +} From b994a40dc6fa2c59198691abaad18546e7759995 Mon Sep 17 00:00:00 2001 From: Mikhail Fedoseev Date: Thu, 6 Mar 2025 23:08:20 +0400 Subject: [PATCH 09/10] Add tests --- .../io/jmix/dependency/cli/version/JmixVersion.java | 4 ++++ .../jmix/deptool/test/AdditionalDependenciesTest.java | 11 ++++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/deptool/src/main/java/io/jmix/dependency/cli/version/JmixVersion.java b/deptool/src/main/java/io/jmix/dependency/cli/version/JmixVersion.java index af81735..9a32811 100644 --- a/deptool/src/main/java/io/jmix/dependency/cli/version/JmixVersion.java +++ b/deptool/src/main/java/io/jmix/dependency/cli/version/JmixVersion.java @@ -25,6 +25,10 @@ public JmixVersion withPatch(int patch) { return new JmixVersion(major, minor, patch, suffix); } + public JmixVersion withSuffix(String suffix) { + return new JmixVersion(major, minor, patch, suffix); + } + public boolean isSnapshot() { return JmixVersionUtils.isSnapshot(versionString()); } diff --git a/deptool/src/test/java/io/jmix/deptool/test/AdditionalDependenciesTest.java b/deptool/src/test/java/io/jmix/deptool/test/AdditionalDependenciesTest.java index 05107c8..07484ea 100644 --- a/deptool/src/test/java/io/jmix/deptool/test/AdditionalDependenciesTest.java +++ b/deptool/src/test/java/io/jmix/deptool/test/AdditionalDependenciesTest.java @@ -16,14 +16,15 @@ public void testNpmDependencies() throws IOException { try (var fileContent = PACKAGE_LOCK.findFileContent(jmixVersion)) { byte[] package_lock_jmix_2_5 = fileContent.readAllBytes(); Assertions.assertNotNull(package_lock_jmix_2_5); - testPackageJson(jmixVersion.withPatch(5), package_lock_jmix_2_5, true); - Assertions.assertThrows(NullPointerException.class, () -> { - testPackageJson(jmixVersion.withMajor(1), package_lock_jmix_2_5, false); - }); + testPackageJson(jmixVersion.withPatch(5), package_lock_jmix_2_5); + testPackageJson(jmixVersion.withPatch(999).withSuffix("-SNAPSHOT"), package_lock_jmix_2_5); + testPackageJson(jmixVersion.withSuffix("-RC1"), package_lock_jmix_2_5); + Assertions.assertThrows(NullPointerException.class, () -> + testPackageJson(jmixVersion.withMajor(1), package_lock_jmix_2_5)); } } - private void testPackageJson(JmixVersion jmixVersion, byte[] expected, boolean shouldBeEquals) throws IOException { + private void testPackageJson(JmixVersion jmixVersion, byte[] expected) throws IOException { try (var content = PACKAGE_LOCK.findFileContent(jmixVersion)) { byte[] actual = content.readAllBytes(); Assertions.assertNotNull(actual); From 88b1d19528538a2f95bf4a4be69c4624f2f256ad Mon Sep 17 00:00:00 2001 From: Mikhail Fedoseev Date: Fri, 7 Mar 2025 15:28:49 +0400 Subject: [PATCH 10/10] Improve snapshot versions support --- .../additional/AdditionalDependencyType.java | 65 +++++++++++++++++-- .../dependency/cli/version/JmixVersion.java | 4 ++ .../io/jmix/deptool/test/JmixVersionTest.java | 32 +++++++++ 3 files changed, 94 insertions(+), 7 deletions(-) diff --git a/deptool/src/main/java/io/jmix/dependency/cli/dependency/additional/AdditionalDependencyType.java b/deptool/src/main/java/io/jmix/dependency/cli/dependency/additional/AdditionalDependencyType.java index 4c02eb5..e749ebe 100644 --- a/deptool/src/main/java/io/jmix/dependency/cli/dependency/additional/AdditionalDependencyType.java +++ b/deptool/src/main/java/io/jmix/dependency/cli/dependency/additional/AdditionalDependencyType.java @@ -1,13 +1,27 @@ package io.jmix.dependency.cli.dependency.additional; import io.jmix.dependency.cli.version.JmixVersion; +import io.jmix.dependency.cli.version.JmixVersionUtils; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.filefilter.RegexFileFilter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.io.File; import java.io.InputStream; +import java.net.URL; +import java.nio.file.Paths; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; public enum AdditionalDependencyType { NPM("npm"); + private static final Logger log = LoggerFactory.getLogger(AdditionalDependencyType.class); + private static final String ADDITIONAL_DEPENDENCIES_RESOURCES_DIR = "jmix-dependencies/additional"; + private final String directoryName; AdditionalDependencyType(String directoryName) { @@ -21,13 +35,10 @@ public String getDirectoryName() { InputStream findFileContent(JmixVersion jmixVersion, String fileName) { InputStream resource = null; try { - if (!jmixVersion.isStable()) { - for (int patch = 0; patch <= jmixVersion.patch(); patch++) { - if (resource != null) { - break; - } - String versionString = jmixVersion.withPatch(patch).versionString(false); - resource = findResourceAsStream(versionString, fileName); + if (jmixVersion.isSnapshot()) { + String latestVersion = findLatestVersionForMinor(jmixVersion); + if (latestVersion != null) { + resource = findResourceAsStream(latestVersion, fileName); } } else { for (int patch = jmixVersion.patch(); patch >= 0; patch--) { @@ -45,6 +56,46 @@ InputStream findFileContent(JmixVersion jmixVersion, String fileName) { return resource; } + /** + * Find the latest version in minor range. + * For example, we have 2.5.0, 2.5.5, 2.6.0, 3.0.0 versions, then: + *
    + *
  • 1.5.0 -> null
  • + *
  • 2.0.0 -> null
  • + *
  • 2.5.0 -> 2.5.5
  • + *
  • 2.5.2 -> 2.5.5
  • + *
  • 2.5.9 -> 2.5.5
  • + *
  • 3.0.0-> 3.0.0
  • + *
  • 3.1.0 -> null
  • + *
      + */ + private String findLatestVersionForMinor(JmixVersion jmixVersion) { + try { + URL resourcesDirUrl = getClassLoader().getResource(getVersionsDir()); + if (resourcesDirUrl == null) { + return null; + } + + File resourcesDir = Paths.get(resourcesDirUrl.toURI()).toFile(); + Collection children = FileUtils.listFilesAndDirs(resourcesDir, + new RegexFileFilter("ignoreAll"), + new RegexFileFilter("[\\d.-]*")); + + List latestVersion = children.stream() + .filter(File::isDirectory) + .map(File::getName) + .filter(name -> name.startsWith(jmixVersion.majorMinor())) + .collect(Collectors.toList()); + + JmixVersionUtils.sort(latestVersion); + + return latestVersion.stream().findFirst().orElse(null); + } catch (Exception e) { + log.warn("Can not find additional dependencies resources for latest version", e); + return null; + } + } + private InputStream findResourceAsStream(String jmixVersion, String fileName) { return getClassLoader().getResourceAsStream(getFilePath(jmixVersion, fileName)); diff --git a/deptool/src/main/java/io/jmix/dependency/cli/version/JmixVersion.java b/deptool/src/main/java/io/jmix/dependency/cli/version/JmixVersion.java index 9a32811..108db3a 100644 --- a/deptool/src/main/java/io/jmix/dependency/cli/version/JmixVersion.java +++ b/deptool/src/main/java/io/jmix/dependency/cli/version/JmixVersion.java @@ -41,6 +41,10 @@ public boolean isStable() { return JmixVersionUtils.isStable(versionString()); } + public String majorMinor() { + return JmixVersionUtils.getMinorVersion(versionString(false)); + } + public String versionString() { return versionString(true); } diff --git a/deptool/src/test/java/io/jmix/deptool/test/JmixVersionTest.java b/deptool/src/test/java/io/jmix/deptool/test/JmixVersionTest.java index 98f7e5f..81fd2ba 100644 --- a/deptool/src/test/java/io/jmix/deptool/test/JmixVersionTest.java +++ b/deptool/src/test/java/io/jmix/deptool/test/JmixVersionTest.java @@ -1,10 +1,14 @@ package io.jmix.deptool.test; import io.jmix.dependency.cli.version.JmixVersion; +import io.jmix.dependency.cli.version.JmixVersionUtils; import org.junit.jupiter.api.Test; +import org.opentest4j.AssertionFailedError; +import java.util.ArrayList; import java.util.List; import java.util.function.Function; +import java.util.stream.Collectors; import static org.junit.jupiter.api.Assertions.*; @@ -65,5 +69,33 @@ public void testVersionComparing() { assertTrue(compareVersions.apply(dynamicVersion) > 0); assertTrue(compareVersions.apply(dynamicVersion.withMajor(1).withMinor(4)) < 0); assertEquals(0, compareVersions.apply(dynamicVersion.withMajor(1))); + + var unsortedVersions = new ArrayList<>(List.of( + "2.2.2", + "1.5.0", + "1.4.5", + "3.1.0", + "2.1.0" + )); + + var sortedVersions = List.of( + "3.1.0", + "2.2.2", + "2.1.0", + "1.5.0", + "1.4.5" + ); + + List unsortedJmixVersions = unsortedVersions.stream().map(JmixVersion::from).toList(); + List unsortedJmixVersions2 = new ArrayList<>(unsortedJmixVersions); + + assertIterableEquals(unsortedJmixVersions, unsortedJmixVersions2); + + List sortedJmixVersions = unsortedJmixVersions2.stream().sorted().collect(Collectors.toList()); + assertThrows(AssertionFailedError.class, () -> assertIterableEquals(sortedJmixVersions, unsortedJmixVersions)); + + assertThrows(AssertionFailedError.class, () -> assertIterableEquals(sortedVersions, unsortedVersions)); + JmixVersionUtils.sort(unsortedVersions); + assertIterableEquals(sortedVersions, unsortedVersions); } }