This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push: new bce2d90c45b [CAMEL-18646] Provide custom configuration (#8661) bce2d90c45b is described below commit bce2d90c45bcf10e7efc0422714664fb227b7def Author: Gilvan Filho <gilvan.sfi...@gmail.com> AuthorDate: Mon Nov 7 12:09:21 2022 -0300 [CAMEL-18646] Provide custom configuration (#8661) Allows user to provide a custom git config file through a endpoint query param --- .../camel/component/git/GitEndpointConfigurer.java | 6 ++ .../camel/component/git/GitEndpointUriFactory.java | 3 +- .../org/apache/camel/component/git/git.json | 3 +- .../camel-git/src/main/docs/git-component.adoc | 15 +++ .../camel/component/CustomConfigSystemReader.java | 85 +++++++++++++++ .../apache/camel/component/RepositoryFactory.java | 114 +++++++++++++++++++++ .../apache/camel/component/git/GitEndpoint.java | 14 +++ .../git/consumer/AbstractGitConsumer.java | 20 +--- .../camel/component/git/producer/GitProducer.java | 15 +-- .../component/git/consumer/GitConsumerTest.java | 24 ++++- components/camel-git/src/test/resources/git.config | 2 + 11 files changed, 270 insertions(+), 31 deletions(-) diff --git a/components/camel-git/src/generated/java/org/apache/camel/component/git/GitEndpointConfigurer.java b/components/camel-git/src/generated/java/org/apache/camel/component/git/GitEndpointConfigurer.java index 422aa5674bc..228a4041b48 100644 --- a/components/camel-git/src/generated/java/org/apache/camel/component/git/GitEndpointConfigurer.java +++ b/components/camel-git/src/generated/java/org/apache/camel/component/git/GitEndpointConfigurer.java @@ -31,6 +31,8 @@ public class GitEndpointConfigurer extends PropertyConfigurerSupport implements case "exceptionHandler": target.setExceptionHandler(property(camelContext, org.apache.camel.spi.ExceptionHandler.class, value)); return true; case "exchangepattern": case "exchangePattern": target.setExchangePattern(property(camelContext, org.apache.camel.ExchangePattern.class, value)); return true; + case "gitconfigfile": + case "gitConfigFile": target.setGitConfigFile(property(camelContext, java.lang.String.class, value)); return true; case "lazystartproducer": case "lazyStartProducer": target.setLazyStartProducer(property(camelContext, boolean.class, value)); return true; case "operation": target.setOperation(property(camelContext, java.lang.String.class, value)); return true; @@ -62,6 +64,8 @@ public class GitEndpointConfigurer extends PropertyConfigurerSupport implements case "exceptionHandler": return org.apache.camel.spi.ExceptionHandler.class; case "exchangepattern": case "exchangePattern": return org.apache.camel.ExchangePattern.class; + case "gitconfigfile": + case "gitConfigFile": return java.lang.String.class; case "lazystartproducer": case "lazyStartProducer": return boolean.class; case "operation": return java.lang.String.class; @@ -94,6 +98,8 @@ public class GitEndpointConfigurer extends PropertyConfigurerSupport implements case "exceptionHandler": return target.getExceptionHandler(); case "exchangepattern": case "exchangePattern": return target.getExchangePattern(); + case "gitconfigfile": + case "gitConfigFile": return target.getGitConfigFile(); case "lazystartproducer": case "lazyStartProducer": return target.isLazyStartProducer(); case "operation": return target.getOperation(); diff --git a/components/camel-git/src/generated/java/org/apache/camel/component/git/GitEndpointUriFactory.java b/components/camel-git/src/generated/java/org/apache/camel/component/git/GitEndpointUriFactory.java index 0dd639fff86..2ae91733427 100644 --- a/components/camel-git/src/generated/java/org/apache/camel/component/git/GitEndpointUriFactory.java +++ b/components/camel-git/src/generated/java/org/apache/camel/component/git/GitEndpointUriFactory.java @@ -21,12 +21,13 @@ public class GitEndpointUriFactory extends org.apache.camel.support.component.En private static final Set<String> SECRET_PROPERTY_NAMES; private static final Set<String> MULTI_VALUE_PREFIXES; static { - Set<String> props = new HashSet<>(15); + Set<String> props = new HashSet<>(16); props.add("allowEmpty"); props.add("branchName"); props.add("bridgeErrorHandler"); props.add("exceptionHandler"); props.add("exchangePattern"); + props.add("gitConfigFile"); props.add("lazyStartProducer"); props.add("localPath"); props.add("operation"); diff --git a/components/camel-git/src/generated/resources/org/apache/camel/component/git/git.json b/components/camel-git/src/generated/resources/org/apache/camel/component/git/git.json index 7dcb8c41c80..0ba084eb632 100644 --- a/components/camel-git/src/generated/resources/org/apache/camel/component/git/git.json +++ b/components/camel-git/src/generated/resources/org/apache/camel/component/git/git.json @@ -55,6 +55,7 @@ "tagName": { "kind": "parameter", "displayName": "Tag Name", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The tag name to work on" }, "targetBranchName": { "kind": "parameter", "displayName": "Target Branch Name", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "master", "description": "Name of target branch in merge operation. If not supplied will try to use init.defaultBranch git configs. If not configured will use default value" }, "username": { "kind": "parameter", "displayName": "Username", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Remote repository username" }, - "lazyStartProducer": { "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may other [...] + "lazyStartProducer": { "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may other [...] + "gitConfigFile": { "kind": "parameter", "displayName": "Git Config File", "group": "advanced", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "A String with path to a .gitconfig file" } } } diff --git a/components/camel-git/src/main/docs/git-component.adoc b/components/camel-git/src/main/docs/git-component.adoc index 0080cad95f7..957a29a51c6 100644 --- a/components/camel-git/src/main/docs/git-component.adoc +++ b/components/camel-git/src/main/docs/git-component.adoc @@ -83,5 +83,20 @@ from("git:///tmp/testRepo?type=commit") .to(....) --------------------------------------- +== Custom config file +By default camel-git will load ``.gitconfig`` file from user home folder. You +can override this by providing your own ``.gitconfig`` file. + +[source,java] +--------------------------------------- +from("git:///tmp/testRepo?type=commit&gitConfigFile=file:/tmp/configfile") + .to(....) //will load from os dirs + +from("git:///tmp/testRepo?type=commit&gitConfigFile=classpath:configfile") + .to(....) //will load from resources dir + +from("git:///tmp/testRepo?type=commit&gitConfigFile=http://somedomain.xyz/gitconfigfile") + .to(....) //will load from http. You could also use https +--------------------------------------- include::spring-boot:partial$starter.adoc[] diff --git a/components/camel-git/src/main/java/org/apache/camel/component/CustomConfigSystemReader.java b/components/camel-git/src/main/java/org/apache/camel/component/CustomConfigSystemReader.java new file mode 100644 index 00000000000..df3d882528f --- /dev/null +++ b/components/camel-git/src/main/java/org/apache/camel/component/CustomConfigSystemReader.java @@ -0,0 +1,85 @@ +/* + * 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.camel.component; + +import java.io.File; + +import org.eclipse.jgit.lib.Config; +import org.eclipse.jgit.storage.file.FileBasedConfig; +import org.eclipse.jgit.util.FS; +import org.eclipse.jgit.util.SystemReader; + +public class CustomConfigSystemReader extends SystemReader { + private static final SystemReader PROXY = SystemReader.getInstance(); + private File userGitConfig; + + public CustomConfigSystemReader(File userGitConfig) { + super(); + this.userGitConfig = userGitConfig; + } + + @Override + public String getenv(String variable) { + return PROXY.getenv(variable); + } + + @Override + public String getHostname() { + return PROXY.getHostname(); + } + + @Override + public String getProperty(String key) { + return PROXY.getProperty(key); + } + + @Override + public long getCurrentTime() { + return PROXY.getCurrentTime(); + } + + @Override + public int getTimezone(long when) { + return PROXY.getTimezone(when); + } + + @Override + public FileBasedConfig openUserConfig(Config parent, FS fs) { + return new FileBasedConfig(parent, userGitConfig, fs); + } + + @Override + public FileBasedConfig openJGitConfig(Config parent, FS fs) { + return PROXY.openJGitConfig(parent, fs); + } + + // Return an empty system configuration, based on example in SystemReader.Default#openSystemConfig + @Override + public FileBasedConfig openSystemConfig(Config parent, FS fs) { + return new FileBasedConfig(parent, null, fs) { + @Override + public void load() { + } + + @Override + public boolean isOutdated() { + return false; + } + }; + } + +} diff --git a/components/camel-git/src/main/java/org/apache/camel/component/RepositoryFactory.java b/components/camel-git/src/main/java/org/apache/camel/component/RepositoryFactory.java new file mode 100644 index 00000000000..2950415e39a --- /dev/null +++ b/components/camel-git/src/main/java/org/apache/camel/component/RepositoryFactory.java @@ -0,0 +1,114 @@ +/* + * 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.camel.component; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.URL; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.List; + +import org.apache.camel.RuntimeCamelException; +import org.apache.camel.component.git.GitEndpoint; +import org.apache.camel.support.ResourceHelper; +import org.apache.camel.util.ObjectHelper; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.storage.file.FileRepositoryBuilder; +import org.eclipse.jgit.util.SystemReader; + +public abstract class RepositoryFactory { + + private static final SystemReader DEFAULT_INSTANCE; + private static final List<String> VALID_SCHEMES = Arrays.asList("classpath:", "file:", "http:", "https:"); + + static { + DEFAULT_INSTANCE = SystemReader.getInstance(); + } + + private RepositoryFactory() { + } + + public static Repository of(GitEndpoint endpoint) { + if (ObjectHelper.isNotEmpty(endpoint.getGitConfigFile())) { + return resolveConfigFile(endpoint, endpoint.getGitConfigFile()); + } + return getRepository(endpoint, DEFAULT_INSTANCE); + } + + private static Repository resolveConfigFile(GitEndpoint endpoint, String uri) { + if (ObjectHelper.isEmpty(uri)) { + throw new IllegalArgumentException("URI to git config file must be supplied"); + } + + if (!ResourceHelper.hasScheme(uri) || !VALID_SCHEMES.contains(ResourceHelper.getScheme(uri))) { + throw new IllegalArgumentException( + "URI to git config file must have scheme:path pattern where scheme could be classpath, file, http or https"); + } + + String schema = ResourceHelper.getScheme(uri); + String path = uri.substring(schema.length()); + + File gitConfigFile; + if (ResourceHelper.isClasspathUri(uri)) { + gitConfigFile = new File(endpoint.getClass().getClassLoader().getResource(path).getFile()); + } else if (ResourceHelper.isHttpUri(uri)) { + try { + gitConfigFile = getTempFileFromHttp(uri); + } catch (IOException e) { + throw new RuntimeCamelException(String.format("Something went wrong when loading: %s", uri), e); + } + } else { //load from system + gitConfigFile = new File(path); + if (Files.isDirectory(gitConfigFile.toPath()) || !Files.isReadable(gitConfigFile.toPath())) { + throw new IllegalArgumentException( + String.format( + "The configuration file at %s is unreadable (either missing, lacking proper access permission or is not a regular file)", + path)); + } + } + + return getRepository(endpoint, new CustomConfigSystemReader(gitConfigFile)); + } + + private static Repository getRepository(GitEndpoint endpoint, SystemReader instance) { + FileRepositoryBuilder builder = new FileRepositoryBuilder(); + try { + SystemReader.setInstance(instance); + // scan environment GIT_* variables + return builder.setGitDir(new File(endpoint.getLocalPath(), ".git")).readEnvironment() + .findGitDir() // scan up the file system tree + .build(); + } catch (IOException e) { + throw new RuntimeCamelException( + String.format("There was an error opening the repository at %s", endpoint.getLocalPath()), e); + } + } + + private static File getTempFileFromHttp(String url) throws IOException { + Path tempFile = Files.createTempFile(null, null); + FileOutputStream outputStream = new FileOutputStream(tempFile.toString()); + ReadableByteChannel byteChannel = Channels.newChannel(new URL(url).openStream()); + outputStream.getChannel().transferFrom(byteChannel, 0, Long.MAX_VALUE); + return tempFile.toFile(); + } + +} diff --git a/components/camel-git/src/main/java/org/apache/camel/component/git/GitEndpoint.java b/components/camel-git/src/main/java/org/apache/camel/component/git/GitEndpoint.java index 8537f2f3071..165ac92efcd 100644 --- a/components/camel-git/src/main/java/org/apache/camel/component/git/GitEndpoint.java +++ b/components/camel-git/src/main/java/org/apache/camel/component/git/GitEndpoint.java @@ -77,6 +77,9 @@ public class GitEndpoint extends DefaultEndpoint { label = "producer") private String operation; + @UriParam(description = "A String with path to a .gitconfig file", label = "advanced") + private String gitConfigFile; + public GitEndpoint(String uri, GitComponent component) { super(uri, component); } @@ -219,4 +222,15 @@ public class GitEndpoint extends DefaultEndpoint { public void setTargetBranchName(String targetBranchName) { this.targetBranchName = targetBranchName; } + + /** + * A String with path to a .gitconfig file", label = "producer,consumer,advanced + */ + public String getGitConfigFile() { + return this.gitConfigFile; + } + + public void setGitConfigFile(String gitConfigFile) { + this.gitConfigFile = gitConfigFile; + } } diff --git a/components/camel-git/src/main/java/org/apache/camel/component/git/consumer/AbstractGitConsumer.java b/components/camel-git/src/main/java/org/apache/camel/component/git/consumer/AbstractGitConsumer.java index a99156224ae..355d324901f 100644 --- a/components/camel-git/src/main/java/org/apache/camel/component/git/consumer/AbstractGitConsumer.java +++ b/components/camel-git/src/main/java/org/apache/camel/component/git/consumer/AbstractGitConsumer.java @@ -16,15 +16,12 @@ */ package org.apache.camel.component.git.consumer; -import java.io.File; -import java.io.IOException; - import org.apache.camel.Processor; +import org.apache.camel.component.RepositoryFactory; import org.apache.camel.component.git.GitEndpoint; import org.apache.camel.support.ScheduledPollConsumer; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.lib.Repository; -import org.eclipse.jgit.storage.file.FileRepositoryBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -57,20 +54,11 @@ public abstract class AbstractGitConsumer extends ScheduledPollConsumer { git.close(); } - private Repository getLocalRepository() throws IOException { - FileRepositoryBuilder builder = new FileRepositoryBuilder(); - try { - // scan environment GIT_* variables - return builder.setGitDir(new File(endpoint.getLocalPath(), ".git")).readEnvironment() - .findGitDir() // scan up the file system tree - .build(); - } catch (IOException e) { - LOG.error("There was an error, cannot open {} repository", endpoint.getLocalPath()); - throw e; - } + private Repository getLocalRepository() { + return RepositoryFactory.of(endpoint); } - protected Repository getRepository() { + public Repository getRepository() { return repo; } diff --git a/components/camel-git/src/main/java/org/apache/camel/component/git/producer/GitProducer.java b/components/camel-git/src/main/java/org/apache/camel/component/git/producer/GitProducer.java index 51267dc1d47..3b9c9e35e58 100644 --- a/components/camel-git/src/main/java/org/apache/camel/component/git/producer/GitProducer.java +++ b/components/camel-git/src/main/java/org/apache/camel/component/git/producer/GitProducer.java @@ -24,6 +24,7 @@ import java.util.Properties; import java.util.Set; import org.apache.camel.Exchange; +import org.apache.camel.component.RepositoryFactory; import org.apache.camel.component.git.GitConstants; import org.apache.camel.component.git.GitEndpoint; import org.apache.camel.support.DefaultProducer; @@ -46,7 +47,6 @@ import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevWalk; -import org.eclipse.jgit.storage.file.FileRepositoryBuilder; import org.eclipse.jgit.transport.PushResult; import org.eclipse.jgit.transport.RemoteConfig; import org.eclipse.jgit.transport.URIish; @@ -658,17 +658,8 @@ public class GitProducer extends DefaultProducer { updateExchange(exchange, result); } - private Repository getLocalRepository() throws IOException { - FileRepositoryBuilder builder = new FileRepositoryBuilder(); - try { - // scan environment GIT_* variables - return builder.setGitDir(new File(endpoint.getLocalPath(), ".git")).readEnvironment() - .findGitDir() // scan up the file system tree - .build(); - } catch (IOException e) { - LOG.error("There was an error, cannot open {} repository", endpoint.getLocalPath()); - throw e; - } + private Repository getLocalRepository() { + return RepositoryFactory.of(endpoint); } private void updateExchange(Exchange exchange, Object body) { diff --git a/components/camel-git/src/test/java/org/apache/camel/component/git/consumer/GitConsumerTest.java b/components/camel-git/src/test/java/org/apache/camel/component/git/consumer/GitConsumerTest.java index c99a570ee83..6bf059fde31 100644 --- a/components/camel-git/src/test/java/org/apache/camel/component/git/consumer/GitConsumerTest.java +++ b/components/camel-git/src/test/java/org/apache/camel/component/git/consumer/GitConsumerTest.java @@ -29,6 +29,7 @@ import org.eclipse.jgit.lib.Ref; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; public class GitConsumerTest extends GitTestSupport { @@ -160,6 +161,20 @@ public class GitConsumerTest extends GitTestSupport { git.close(); } + @Test + public void injectConfigFileTest() throws Exception { + GitBranchConsumer consumer; + + consumer = (GitBranchConsumer) context.getRoute("injectConfigFileFromClasspath").getConsumer(); + assertEquals("fromClasspath", consumer.getRepository().getConfig().getString("init", null, "defaultBranch")); + + consumer = (GitBranchConsumer) context.getRoute("injectConfigFileFromHttp").getConsumer(); + assertEquals("fromHttp", consumer.getRepository().getConfig().getString("init", null, "defaultBranch")); + + consumer = (GitBranchConsumer) context.getRoute("defaultBranchTest").getConsumer(); + assertNull(consumer.getRepository().getConfig().getString("init", null, "defaultBranch")); + } + @Override protected RouteBuilder createRouteBuilder() { return new RouteBuilder() { @@ -175,7 +190,14 @@ public class GitConsumerTest extends GitTestSupport { from("git://" + gitLocalRepo + "?type=commit&branchName=master").to("mock:result-commit"); from("git://" + gitLocalRepo + "?type=commit&branchName=notexisting").to("mock:result-commit-notexistent"); from("git://" + gitLocalRepo + "?type=tag").to("mock:result-tag"); - from("git://" + gitLocalRepo + "?type=branch").to("mock:result-branch"); + from("git://" + gitLocalRepo + "?type=branch&gitConfigFile=classpath:git.config") + .id("injectConfigFileFromClasspath") + .to("mock:result-branch-configfile"); + from("git://" + gitLocalRepo + + "?type=branch&gitConfigFile=https://gist.githubusercontent.com/gilvansfilho/a61f6ab811a5e8e9d46c4fba1235abc1/raw/a1f614c90e29f1cdd83534aa913f5d276beace2c/gitconfig") + .id("injectConfigFileFromHttp") + .to("mock:result-branch-configfile"); + from("git://" + gitLocalRepo + "?type=branch").id("defaultBranchTest").to("mock:result-branch"); } }; } diff --git a/components/camel-git/src/test/resources/git.config b/components/camel-git/src/test/resources/git.config new file mode 100644 index 00000000000..b97a502c08a --- /dev/null +++ b/components/camel-git/src/test/resources/git.config @@ -0,0 +1,2 @@ +[init] + defaultBranch = fromClasspath