This is an automated email from the ASF dual-hosted git repository.

apkhmv pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git


The following commit(s) were added to refs/heads/main by this push:
     new 107e2c73bb IGNITE-19291 Generate default node configuration file at 
compile-time (#2357)
107e2c73bb is described below

commit 107e2c73bb766f732effd0401c2608fae0c059b8
Author: Cyrill <cyrill.si...@gmail.com>
AuthorDate: Fri Jul 28 12:43:47 2023 +0300

    IGNITE-19291 Generate default node configuration file at compile-time 
(#2357)
    
    Now all distributions contains a node configuration file with all defaults 
set.
---
 modules/runner/build.gradle                        |  28 +++++
 .../configuration/generator/DefaultsGenerator.java | 116 +++++++++++++++++++++
 packaging/build.gradle                             |   4 +-
 packaging/db/build.gradle                          |  53 ++++++----
 4 files changed, 182 insertions(+), 19 deletions(-)

diff --git a/modules/runner/build.gradle b/modules/runner/build.gradle
index 830c2c03c2..e793f5cf0b 100644
--- a/modules/runner/build.gradle
+++ b/modules/runner/build.gradle
@@ -23,6 +23,23 @@ apply from: 
"$rootDir/buildscripts/java-integration-test.gradle"
 
 description = 'ignite-runner'
 
+sourceSets {
+    defaultsGenerator {
+        compileClasspath += sourceSets.main.output
+        runtimeClasspath += sourceSets.main.output
+    }
+}
+
+configurations {
+    defaultsGeneratorImplementation.extendsFrom implementation
+    defaultsGenerator {
+        canBeConsumed = true
+        canBeResolved = false
+        // this configuration will share the same dependencies as the main one
+        extendsFrom implementation, runtimeOnly
+    }
+}
+
 dependencies {
     annotationProcessor project(':ignite-configuration-annotation-processor')
     annotationProcessor libs.picocli.annotation.processor
@@ -207,3 +224,14 @@ jar {
         )
     }
 }
+
+
+tasks.register('defaultsJar', Jar) {
+    from sourceSets.defaultsGenerator.output
+    archiveAppendix = "generator"
+}
+
+artifacts {
+    // declare both jars to provide enough dependencies to the caller
+    defaultsGenerator defaultsJar, jar
+}
diff --git 
a/modules/runner/src/defaultsGenerator/java/org/apache/ignite/internal/configuration/generator/DefaultsGenerator.java
 
b/modules/runner/src/defaultsGenerator/java/org/apache/ignite/internal/configuration/generator/DefaultsGenerator.java
new file mode 100644
index 0000000000..d17b08e1c4
--- /dev/null
+++ 
b/modules/runner/src/defaultsGenerator/java/org/apache/ignite/internal/configuration/generator/DefaultsGenerator.java
@@ -0,0 +1,116 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.configuration.generator;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+import org.apache.ignite.configuration.ConfigurationModule;
+import org.apache.ignite.configuration.RootKey;
+import org.apache.ignite.configuration.annotation.ConfigurationType;
+import org.apache.ignite.internal.configuration.ConfigurationChanger;
+import 
org.apache.ignite.internal.configuration.ConfigurationChanger.ConfigurationUpdateListener;
+import org.apache.ignite.internal.configuration.ConfigurationModules;
+import org.apache.ignite.internal.configuration.ConfigurationTreeGenerator;
+import org.apache.ignite.internal.configuration.ServiceLoaderModulesProvider;
+import org.apache.ignite.internal.configuration.storage.ConfigurationStorage;
+import 
org.apache.ignite.internal.configuration.storage.LocalFileConfigurationStorage;
+import org.apache.ignite.internal.configuration.tree.InnerNode;
+import 
org.apache.ignite.internal.configuration.validation.ConfigurationValidator;
+import 
org.apache.ignite.internal.configuration.validation.ConfigurationValidatorImpl;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * A generator of the default local configuration file.
+ */
+public class DefaultsGenerator {
+
+    /**
+     * Entry point to the config file generation.
+     *
+     * <p>The generator looks for all available configuration roots with type 
{@link ConfigurationType#LOCAL} in its own classpath,
+     * so please make sure the classpath is properly constructed.
+     *
+     * @param args The first element represents the path to the config file.
+     *     If the file exists and is not empty, the stored configuration will 
be merged with the defaults.
+     *     Please note: the file will be overwritten.
+     */
+    public static void main(String[] args) {
+        if (args.length < 1) {
+            throw new IllegalArgumentException("Please provide the path to the 
config file as an argument");
+        }
+        Path configPath = Paths.get(args[0]);
+
+        ConfigurationChanger changer = null;
+        try {
+            changer = createConfigurationChanger(configPath);
+            changer.start();
+            changer.onDefaultsPersisted().get(5, TimeUnit.SECONDS);
+        } catch (Exception e) {
+            throw new IllegalStateException("Failed to generate defaults file."
+                    + "Please make sure that the classloader for loading 
services is correct.");
+        } finally {
+            if (changer != null) {
+                changer.stop();
+            }
+        }
+    }
+
+    /**
+     * This uses fragments of cluster initialization from {@code IgniteImpl} 
class to set up local configuration framework.
+     */
+    private static ConfigurationChanger createConfigurationChanger(Path 
configPath) {
+
+        ConfigurationModules modules = 
loadConfigurationModules(DefaultsGenerator.class.getClassLoader());
+
+        ConfigurationTreeGenerator localConfigurationGenerator = new 
ConfigurationTreeGenerator(
+                modules.local().rootKeys(),
+                modules.local().internalSchemaExtensions(),
+                modules.local().polymorphicSchemaExtensions()
+        );
+
+        ConfigurationStorage storage = new 
LocalFileConfigurationStorage(configPath, localConfigurationGenerator);
+
+        ConfigurationValidator configurationValidator =
+                
ConfigurationValidatorImpl.withDefaultValidators(localConfigurationGenerator, 
modules.local().validators());
+
+        ConfigurationUpdateListener empty = (oldRoot, newRoot, 
storageRevision, notificationNumber) ->
+                CompletableFuture.completedFuture(null);
+
+        return new ConfigurationChanger(empty, modules.local().rootKeys(), 
storage, configurationValidator) {
+            @Override
+            public InnerNode createRootNode(RootKey<?, ?> rootKey) {
+                return 
localConfigurationGenerator.instantiateNode(rootKey.schemaClass());
+            }
+        };
+    }
+
+    private static ConfigurationModules loadConfigurationModules(@Nullable 
ClassLoader classLoader) {
+        var modulesProvider = new ServiceLoaderModulesProvider();
+        List<ConfigurationModule> modules = 
modulesProvider.modules(classLoader);
+
+        if (modules.isEmpty()) {
+            throw new IllegalStateException("No configuration modules were 
loaded. "
+                    + "Please make sure that the classloader for loading 
services is correct.");
+        }
+
+        return new ConfigurationModules(modules);
+    }
+}
diff --git a/packaging/build.gradle b/packaging/build.gradle
index 5efc65a272..17ac134c73 100644
--- a/packaging/build.gradle
+++ b/packaging/build.gradle
@@ -36,6 +36,7 @@ configurations {
     cliZip
     dbZip
     release
+    localDefaults
 }
 
 dependencies {
@@ -47,6 +48,7 @@ dependencies {
     release project(path: ':packaging-db', configuration: 'dbRelease')
     release project(path: ':ignite-jdbc', configuration: 'jdbcRelease')
     release project(path: ':platforms', configuration: 'platformsRelease')
+    localDefaults project(path: ':packaging-db', configuration: 
'localDefaults')
 }
 
 // Task that generates start script for cli
@@ -99,7 +101,7 @@ docker {
                 from "$rootDir/assembly/README.md"
             }
             into('etc') {
-                from 'config/ignite-config.conf'
+                from configurations.localDefaults
                 from 'docker/ignite.java.util.logging.properties'
             }
             into('lib') {
diff --git a/packaging/db/build.gradle b/packaging/db/build.gradle
index d2df58d25f..eeee9c613c 100644
--- a/packaging/db/build.gradle
+++ b/packaging/db/build.gradle
@@ -34,10 +34,26 @@ import org.gradle.crypto.checksum.Checksum
 
 configurations {
     dbArtifacts
+    defaultsGenerator
+    dbZip {
+        canBeConsumed = true
+        canBeResolved = false
+    }
+    dbRelease {
+        canBeConsumed = true
+        canBeResolved = false
+    }
+    localDefaults {
+        canBeConsumed = true
+        canBeResolved = false
+    }
 }
 
 dependencies {
-    dbArtifacts(project(':ignite-runner'))
+    dbArtifacts project(':ignite-runner')
+
+    defaultsGenerator configurations.dbArtifacts
+    defaultsGenerator project(path: ':ignite-runner', configuration: 
'defaultsGenerator')
 }
 
 def tokens = [
@@ -71,6 +87,19 @@ task replaceZipScriptVars(type: Copy) {
     into "$buildDir/zip/"
 }
 
+def copyConfig = tasks.register('copyConfig', Copy) {
+    from "$rootDir/packaging/config/ignite-config.conf"
+    into layout.buildDirectory.dir("config")
+}
+
+def generateConfigDefaults = tasks.register('generateConfigDefaults', 
JavaExec) {
+    classpath = configurations.defaultsGenerator
+    mainClass = 
"org.apache.ignite.internal.configuration.generator.DefaultsGenerator"
+    dependsOn copyConfig
+    args layout.buildDirectory.file("config/ignite-config.conf").get()
+    outputs.file layout.buildDirectory.file("config/ignite-config.conf")
+}
+
 distributions {
     main {
         distributionBaseName = 'ignite3-db'
@@ -91,7 +120,7 @@ distributions {
             }
             into('etc') {
                 from "$buildDir/zip/${zipStartScriptTokens.VARS_FILE_NAME}"
-                from "$rootDir/packaging/config/ignite-config.conf"
+                from generateConfigDefaults
                 from "$buildDir/zip/ignite.java.util.logging.properties"
             }
             into('bin') {
@@ -117,16 +146,9 @@ task createChecksums(type: Checksum) {
     checksumAlgorithm = Checksum.Algorithm.SHA512
 }
 
-// Expose zip artifacts to be consumed by others
-configurations {
-    dbZip {
-        canBeConsumed = true
-        canBeResolved = false
-    }
-}
-
 artifacts {
     dbZip(distZip)
+    localDefaults generateConfigDefaults
 }
 
 // Explicitly create task so that the resulting artifact is not added to the 
configuration
@@ -213,7 +235,7 @@ ospackage {
             fileType CONFIG
             from "$buildDir/linux/service/vars.env"
             from "$buildDir/linux/ignite.java.util.logging.properties"
-            from "$rootDir/packaging/config/ignite-config.conf"
+            from generateConfigDefaults
         }
 
         into('etc') {
@@ -224,12 +246,7 @@ ospackage {
     link "/opt/ignite3db", "${packageTokens.INSTALL_DIR}"
 }
 
-configurations {
-    dbRelease {
-        canBeConsumed = true
-        canBeResolved = false
-    }
-}
+
 
 if (project.hasProperty('prepareRelease')) {
     artifacts {
@@ -292,7 +309,7 @@ setupBuilder {
             from('log')
         }
         into('etc') {
-            from "${rootDir}/packaging/config/ignite-config.conf"
+            from generateConfigDefaults
         }
         into('etc') {
             from("ignite.java.util.logging.properties")

Reply via email to