Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support additional npm dependencies #30

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -60,10 +61,22 @@ protected void installNodeTgzDownloader() {
executeCommand(downloaderDir, "npm install node-tgz-downloader");
}

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);
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 {
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);
}
}

protected void copyPackageLock() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<String> repositories;

private JmixVersion parsedVersion;

@Override
public void run() {
parsedVersion = JmixVersion.from(jmixVersion);

if (jmixPluginVersion == null) {
jmixPluginVersion = jmixVersion;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,22 @@
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;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Paths;
import java.util.ArrayList;
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 {

Expand Down Expand Up @@ -54,8 +58,12 @@ public class ResolveNpmCommand implements BaseCommand {
"If credentials are not required then just an URL must be passed", order = 9)
private List<String> repositories;

private JmixVersion parsedVersion;

@Override
public void run() {
parsedVersion = JmixVersion.from(jmixVersion);

if (jmixPluginVersion == null) {
jmixPluginVersion = jmixVersion;
}
Expand All @@ -76,6 +84,7 @@ public void run() {
vaadinClean(jmixGradleClient);
copyStubPackageLock();
resolveDependencies(jmixGradleClient);
resolveAdditionalDependencies();
}

protected void vaadinClean(JmixGradleClient jmixGradleClient) {
Expand Down Expand Up @@ -153,4 +162,45 @@ protected void resolveDependencies(JmixGradleClient jmixGradleClient) {
log.info(result);
}
}

private void resolveAdditionalDependencies() {
try {
File additionalDependenciesDir = Paths.get(resolverProjectPath,
"additional-dependencies").toAbsolutePath().normalize().toFile();
if (additionalDependenciesDir.exists()) {
FileUtils.cleanDirectory(additionalDependenciesDir);
} else if (!additionalDependenciesDir.mkdir()) {
return;
}

resolveAdditionalPackageLockFile(additionalDependenciesDir);

} catch (Exception e) {
log.info("Error when trying to download additional dependencies", e);
}
}

private void resolveAdditionalPackageLockFile(File additionalDependenciesDir) throws IOException {
String packageLockFileName = PACKAGE_LOCK.getFileName();

try (InputStream packageLockContent = PACKAGE_LOCK.findFileContent(parsedVersion)) {
if (packageLockContent == null) {
log.info("-= No additional dependencies was found, skipping this step =-");
return;
}

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);
}
}
}

}
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
package io.jmix.dependency.cli.dependency;

import org.dom4j.*;
import io.jmix.dependency.cli.version.JmixVersionUtils;
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;

import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public class JmixDependencies {

private static final Logger log = LoggerFactory.getLogger(JmixDependencies.class);

public static Set<String> getVersionSpecificJmixDependencies(String jmixVersion, boolean resolveCommercialAddons) {
String minorJmixVersion = getMinorVersion(jmixVersion);
String minorJmixVersion = JmixVersionUtils.getMinorVersion(jmixVersion);
Set<String> 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)
Expand Down Expand Up @@ -48,19 +53,9 @@ private static Set<String> _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
*/
private static String getMinorVersion(String jmixVersion) {
String[] parts = jmixVersion.split("\\.");
return parts[0] + "." + parts[1];
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package io.jmix.dependency.cli.dependency.additional;

import io.jmix.dependency.cli.version.JmixVersion;

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(JmixVersion jmixVersion) {
return getDependencyType().findFileContent(jmixVersion, getFileName());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
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) {
this.directoryName = directoryName;
}

public String getDirectoryName() {
return directoryName;
}

InputStream findFileContent(JmixVersion jmixVersion, String fileName) {
InputStream resource = null;
try {
if (jmixVersion.isSnapshot()) {
String latestVersion = findLatestVersionForMinor(jmixVersion);
if (latestVersion != null) {
resource = findResourceAsStream(latestVersion, 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);
}
}
} catch (NumberFormatException ignored) {
resource = findResourceAsStream(jmixVersion.versionString(false), 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:
* <ul>
* <li>1.5.0 -> null</li>
* <li>2.0.0 -> null</li>
* <li>2.5.0 -> 2.5.5</li>
* <li>2.5.2 -> 2.5.5</li>
* <li>2.5.9 -> 2.5.5</li>
* <li>3.0.0-> 3.0.0</li>
* <li>3.1.0 -> null</li>
* <ul/>
*/
private String findLatestVersionForMinor(JmixVersion jmixVersion) {
try {
URL resourcesDirUrl = getClassLoader().getResource(getVersionsDir());
if (resourcesDirUrl == null) {
return null;
}

File resourcesDir = Paths.get(resourcesDirUrl.toURI()).toFile();
Collection<File> children = FileUtils.listFilesAndDirs(resourcesDir,
new RegexFileFilter("ignoreAll"),
new RegexFileFilter("[\\d.-]*"));

List<String> 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));
}

private String getFilePath(String jmixVersion, String fileName) {
return getResourcesDir(jmixVersion) + "/" + fileName;
}

private String getResourcesDir(String jmixVersion) {
return getVersionsDir() + "/" + jmixVersion;
}

private String getVersionsDir() {
return ADDITIONAL_DEPENDENCIES_RESOURCES_DIR + "/" + getDirectoryName();
}

private ClassLoader getClassLoader() {
return getClass().getClassLoader();
}
}
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -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);
}

Expand Down
12 changes: 12 additions & 0 deletions deptool/src/main/java/io/jmix/dependency/cli/util/StringUtils.java
Original file line number Diff line number Diff line change
@@ -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);
}
}
Loading