Merge with default

This commit is contained in:
Rene Pfeuffer
2020-01-10 10:22:43 +01:00
22 changed files with 625 additions and 206 deletions

View File

@@ -23,7 +23,7 @@
--> -->
<!--- root element of the plugin descriptor --> <!--- root element of the plugin descriptor -->
<!ELEMENT plugin (scm-version|information|child-first-classloader|conditions|resources|dependencies|extension|extension-point|rest-resource|subscriber)*> <!ELEMENT plugin (scm-version|information|child-first-classloader|conditions|resources|dependencies|optional-dependencies|extension|extension-point|rest-resource|subscriber)*>
<!--- major scm-manager version --> <!--- major scm-manager version -->
<!ELEMENT scm-version (#PCDATA)> <!ELEMENT scm-version (#PCDATA)>
@@ -79,13 +79,19 @@
<!--- contains plugin dependencies --> <!--- contains plugin dependencies -->
<!ELEMENT dependencies (dependency)*> <!ELEMENT dependencies (dependency)*>
<!--- sing plugin dependency --> <!--- contains optional plugin dependencies -->
<!ELEMENT optional-dependencies (dependency)*>
<!--- single plugin dependency -->
<!ELEMENT dependency (#PCDATA)> <!ELEMENT dependency (#PCDATA)>
<!-- generated entries --> <!-- generated entries -->
<!--- extension --> <!--- extension -->
<!ELEMENT extension (description|class)*> <!ELEMENT extension (description|class|requires)*>
<!--- requires value -->
<!ELEMENT requires (#PCDATA)>
<!--- class value --> <!--- class value -->
<!ELEMENT class (#PCDATA)> <!ELEMENT class (#PCDATA)>

View File

@@ -20,7 +20,7 @@
}, },
"resolutions": { "resolutions": {
"babel-core": "7.0.0-bridge.0", "babel-core": "7.0.0-bridge.0",
"gitdiff-parser": "https://github.com/scm-manager/gitdiff-parser#6baa7278824ecd17a199d842ca720d0453f68982" "gitdiff-parser": "https://github.com/scm-manager/gitdiff-parser#ed3fe7de73dbb0a06c3e6adbbdf22dbae6e66351"
}, },
"babel": { "babel": {
"presets": [ "presets": [

View File

@@ -284,6 +284,12 @@
<version>${jackson.version}</version> <version>${jackson.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>${hibernate-validator.version}</version>
</dependency>
<!-- JUnit 5 --> <!-- JUnit 5 -->
<dependency> <dependency>
@@ -843,6 +849,7 @@
<jackson.version>2.10.0</jackson.version> <jackson.version>2.10.0</jackson.version>
<guice.version>4.0</guice.version> <guice.version>4.0</guice.version>
<jaxb.version>2.3.0</jaxb.version> <jaxb.version>2.3.0</jaxb.version>
<hibernate-validator.version>6.1.0.Final</hibernate-validator.version>
<!-- event bus --> <!-- event bus -->
<legman.version>1.6.1</legman.version> <legman.version>1.6.1</legman.version>

View File

@@ -49,4 +49,15 @@ import java.lang.annotation.Target;
@Target({ ElementType.TYPE }) @Target({ ElementType.TYPE })
@PluginAnnotation("extension") @PluginAnnotation("extension")
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface Extension {} public @interface Extension {
/**
* This extension is loaded only if all of the specified plugins are installed.
* The requires attribute can be used to implement optional extensions.
* A plugin author is able to implement an extension point of an optional plugin and the extension is only loaded if
* all of the specified plugins are installed.
*
* @since 2.0.0
* @return list of required plugins to load this extension
*/
String[] requires() default {};
}

View File

@@ -173,6 +173,13 @@
<artifactId>activation</artifactId> <artifactId>activation</artifactId>
</dependency> </dependency>
<!-- validation -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<!-- util --> <!-- util -->
<dependency> <dependency>
@@ -214,12 +221,6 @@
<artifactId>shiro-unit</artifactId> <artifactId>shiro-unit</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.3.6.Final</version>
<scope>compile</scope>
</dependency>
</dependencies> </dependencies>

View File

@@ -0,0 +1,26 @@
package sonia.scm.plugin;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import java.util.HashSet;
import java.util.Set;
@Getter
@ToString
@NoArgsConstructor
@EqualsAndHashCode
@AllArgsConstructor
@XmlAccessorType(XmlAccessType.FIELD)
public class ExtensionElement {
@XmlElement(name = "class")
private String clazz;
private String description;
private Set<String> requires = new HashSet<>();
}

View File

@@ -38,6 +38,7 @@ package sonia.scm.plugin;
import com.google.common.base.MoreObjects; import com.google.common.base.MoreObjects;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAccessorType;
@@ -76,7 +77,7 @@ public final class InstalledPluginDescriptor extends ScmModule implements Plugin
*/ */
public InstalledPluginDescriptor(int scmVersion, PluginInformation information, public InstalledPluginDescriptor(int scmVersion, PluginInformation information,
PluginResources resources, PluginCondition condition, PluginResources resources, PluginCondition condition,
boolean childFirstClassLoader, Set<String> dependencies) boolean childFirstClassLoader, Set<String> dependencies, Set<String> optionalDependencies)
{ {
this.scmVersion = scmVersion; this.scmVersion = scmVersion;
this.information = information; this.information = information;
@@ -84,6 +85,7 @@ public final class InstalledPluginDescriptor extends ScmModule implements Plugin
this.condition = condition; this.condition = condition;
this.childFirstClassLoader = childFirstClassLoader; this.childFirstClassLoader = childFirstClassLoader;
this.dependencies = dependencies; this.dependencies = dependencies;
this.optionalDependencies = optionalDependencies;
} }
//~--- methods -------------------------------------------------------------- //~--- methods --------------------------------------------------------------
@@ -116,7 +118,8 @@ public final class InstalledPluginDescriptor extends ScmModule implements Plugin
&& Objects.equal(information, other.information) && Objects.equal(information, other.information)
&& Objects.equal(resources, other.resources) && Objects.equal(resources, other.resources)
&& Objects.equal(childFirstClassLoader, other.childFirstClassLoader) && Objects.equal(childFirstClassLoader, other.childFirstClassLoader)
&& Objects.equal(dependencies, other.dependencies); && Objects.equal(dependencies, other.dependencies)
&& Objects.equal(optionalDependencies, other.optionalDependencies);
} }
/** /**
@@ -129,7 +132,7 @@ public final class InstalledPluginDescriptor extends ScmModule implements Plugin
public int hashCode() public int hashCode()
{ {
return Objects.hashCode(scmVersion, condition, information, resources, return Objects.hashCode(scmVersion, condition, information, resources,
childFirstClassLoader, dependencies); childFirstClassLoader, dependencies, optionalDependencies);
} }
/** /**
@@ -149,6 +152,7 @@ public final class InstalledPluginDescriptor extends ScmModule implements Plugin
.add("resources", resources) .add("resources", resources)
.add("childFirstClassLoader", childFirstClassLoader) .add("childFirstClassLoader", childFirstClassLoader)
.add("dependencies", dependencies) .add("dependencies", dependencies)
.add("optionalDependencies", optionalDependencies)
.toString(); .toString();
//J+ //J+
} }
@@ -186,6 +190,27 @@ public final class InstalledPluginDescriptor extends ScmModule implements Plugin
return dependencies; return dependencies;
} }
/**
* Method description
*
*
* @return
*
* @since 2.0.0
*/
public Set<String> getOptionalDependencies() {
if (optionalDependencies == null)
{
optionalDependencies = ImmutableSet.of();
}
return optionalDependencies;
}
public Set<String> getDependenciesInclusiveOptionals() {
return ImmutableSet.copyOf(Iterables.concat(getDependencies(), getOptionalDependencies()));
}
/** /**
* Method description * Method description
* *
@@ -246,6 +271,11 @@ public final class InstalledPluginDescriptor extends ScmModule implements Plugin
@XmlElementWrapper(name = "dependencies") @XmlElementWrapper(name = "dependencies")
private Set<String> dependencies; private Set<String> dependencies;
/** Field description */
@XmlElement(name = "dependency")
@XmlElementWrapper(name = "optional-dependencies")
private Set<String> optionalDependencies;
/** Field description */ /** Field description */
@XmlElement(name = "information") @XmlElement(name = "information")
private PluginInformation information; private PluginInformation information;

View File

@@ -89,9 +89,9 @@ public class ScmModule
* *
* @return * @return
*/ */
public Iterable<Class<?>> getExtensions() public Iterable<ExtensionElement> getExtensions()
{ {
return unwrap(extensions); return nonNull(extensions);
} }
/** /**
@@ -223,7 +223,7 @@ public class ScmModule
/** Field description */ /** Field description */
@XmlElement(name = "extension") @XmlElement(name = "extension")
private Set<ClassElement> extensions; private Set<ExtensionElement> extensions;
/** Field description */ /** Field description */
@XmlElement(name = "rest-provider") @XmlElement(name = "rest-provider")

View File

@@ -33,6 +33,7 @@ package sonia.scm.plugin;
//~--- non-JDK imports -------------------------------------------------------- //~--- non-JDK imports --------------------------------------------------------
import com.google.common.collect.Iterables;
import com.google.common.io.Resources; import com.google.common.io.Resources;
import org.junit.Test; import org.junit.Test;
@@ -69,43 +70,43 @@ public class ScmModuleTest
//J- //J-
assertThat( assertThat(
module.getExtensions(), Iterables.transform(module.getExtensions(), ExtensionElement::getClazz),
containsInAnyOrder( containsInAnyOrder(
String.class, String.class.getName(),
Integer.class Integer.class.getName()
) )
); );
assertThat( assertThat(
module.getExtensionPoints(), module.getExtensionPoints(),
containsInAnyOrder( containsInAnyOrder(
new ExtensionPointElement(String.class, "ext01", true, true), new ExtensionPointElement(String.class, "ext01", true, true),
new ExtensionPointElement(Long.class, "ext02", true, true), new ExtensionPointElement(Long.class, "ext02", true, true),
new ExtensionPointElement(Integer.class, "ext03", false, true) new ExtensionPointElement(Integer.class, "ext03", false, true)
) )
); );
assertThat( assertThat(
module.getEvents(), module.getEvents(),
containsInAnyOrder( containsInAnyOrder(
String.class, String.class,
Boolean.class Boolean.class
) )
); );
assertThat( assertThat(
module.getSubscribers(), module.getSubscribers(),
containsInAnyOrder( containsInAnyOrder(
new SubscriberElement(Long.class, Integer.class, "sub01"), new SubscriberElement(Long.class, Integer.class, "sub01"),
new SubscriberElement(Double.class, Float.class, "sub02") new SubscriberElement(Double.class, Float.class, "sub02")
) )
); );
assertThat( assertThat(
module.getRestProviders(), module.getRestProviders(),
containsInAnyOrder( containsInAnyOrder(
Integer.class, Integer.class,
Long.class Long.class
) )
); );
assertThat( assertThat(
module.getRestResources(), module.getRestResources(),
containsInAnyOrder( containsInAnyOrder(
Float.class, Float.class,
Double.class Double.class

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<module> <module>
<!-- subscribers --> <!-- subscribers -->
<subscriber> <subscriber>
<class>java.lang.Long</class> <class>java.lang.Long</class>
@@ -47,28 +47,32 @@
<extension> <extension>
<class>java.lang.String</class> <class>java.lang.String</class>
<requires>scm-mail-plugin</requires>
<requires>scm-review-plugin</requires>
<description>ext01</description>
</extension> </extension>
<extension> <extension>
<class>java.lang.Integer</class> <class>java.lang.Integer</class>
<description>ext02</description>
</extension> </extension>
<!-- rest providers --> <!-- rest providers -->
<rest-provider> <rest-provider>
<class>java.lang.Integer</class> <class>java.lang.Integer</class>
</rest-provider> </rest-provider>
<rest-provider> <rest-provider>
<class>java.lang.Long</class> <class>java.lang.Long</class>
</rest-provider> </rest-provider>
<!-- jax-rs resources --> <!-- jax-rs resources -->
<rest-resource> <rest-resource>
<class>java.lang.Float</class> <class>java.lang.Float</class>
</rest-resource> </rest-resource>
<rest-resource> <rest-resource>
<class>java.lang.Double</class> <class>java.lang.Double</class>
</rest-resource> </rest-resource>

View File

@@ -0,0 +1,18 @@
export default `diff --git a/Main.java b/Main.java
index 9b5ca13..7ced845 100644
--- a/Main.java
+++ b/Main.java
@@ -1,5 +1,5 @@
class Main {
- public static void main(String[] args) {
+ public static void main(String[] arguments) {
System.out.println("Expect nothing more to happen.");
}
}
diff --git a/conflict.png b/conflict.png
new file mode 100644
index 0000000..7c77c7f
--- /dev/null
+++ b/conflict.png
Binary files differ
`;

View File

@@ -334,6 +334,305 @@ exports[`Storyshots DateFromNow Default 1`] = `
</div> </div>
`; `;
exports[`Storyshots Diff Binaries 1`] = `
Array [
<div
className="sc-iwsKbI czQDxz panel is-size-6"
>
<div
className="panel-heading"
>
<div
className="sc-gZMcBi hiXlnL level"
>
<div
className="sc-gqjmRU jMyrLy level-left is-flex has-cursor-pointer"
onClick={[Function]}
title="Main.java"
>
<i
className="fas fa-angle-down has-text-inherit"
/>
<span
className="sc-VigVT kUVxiT is-ellipsis-overflow is-size-6"
>
Main.java
</span>
<span
className="tag is-info is-outlined sc-jzJRlG fdoJSr is-rounded has-text-weight-normal"
>
modify
</span>
</div>
<div
className="sc-jTzLTM ljPywG level-right is-flex"
>
<div
className="field is-grouped"
>
<div
className="control"
>
<button
className="button is-default is-reduced-mobile"
onClick={[Function]}
type="button"
>
<span
className="icon is-medium"
>
<i
className="fas fa-columns has-text-inherit"
/>
</span>
<span>
diff.sideBySide
</span>
</button>
</div>
</div>
</div>
</div>
</div>
<div
className="panel-block is-paddingless"
>
<table
className="diff diff-unified sc-cSHVUG cHkPoJ unified"
onMouseDown={[Function]}
>
<colgroup>
<col
className="diff-gutter-col"
/>
<col
className="diff-gutter-col"
/>
<col />
</colgroup>
<tbody
className="diff-decoration"
>
<tr>
<td
className="diff-decoration-content"
colSpan={3}
>
<span />
</td>
</tr>
</tbody>
<tbody
className="diff-hunk"
>
<tr
className="diff-line"
>
<td
className="diff-gutter diff-gutter-normal"
onMouseEnter={[Function]}
onMouseLeave={[Function]}
>
1
</td>
<td
className="diff-gutter diff-gutter-normal"
onMouseEnter={[Function]}
onMouseLeave={[Function]}
>
1
</td>
<td
className="diff-code diff-code-normal"
onMouseEnter={[Function]}
onMouseLeave={[Function]}
>
class Main {
</td>
</tr>
<tr
className="diff-line"
>
<td
className="diff-gutter diff-gutter-normal"
onMouseEnter={[Function]}
onMouseLeave={[Function]}
>
2
</td>
<td
className="diff-gutter diff-gutter-normal"
onMouseEnter={[Function]}
onMouseLeave={[Function]}
>
2
</td>
<td
className="diff-code diff-code-normal"
onMouseEnter={[Function]}
onMouseLeave={[Function]}
>
- public static void main(String[] args) {
</td>
</tr>
<tr
className="diff-line"
>
<td
className="diff-gutter diff-gutter-normal"
onMouseEnter={[Function]}
onMouseLeave={[Function]}
>
3
</td>
<td
className="diff-gutter diff-gutter-normal"
onMouseEnter={[Function]}
onMouseLeave={[Function]}
>
3
</td>
<td
className="diff-code diff-code-normal"
onMouseEnter={[Function]}
onMouseLeave={[Function]}
>
+ public static void main(String[] arguments) {
</td>
</tr>
<tr
className="diff-line"
>
<td
className="diff-gutter diff-gutter-normal"
onMouseEnter={[Function]}
onMouseLeave={[Function]}
>
4
</td>
<td
className="diff-gutter diff-gutter-normal"
onMouseEnter={[Function]}
onMouseLeave={[Function]}
>
4
</td>
<td
className="diff-code diff-code-normal"
onMouseEnter={[Function]}
onMouseLeave={[Function]}
>
System.out.println("Expect nothing more to happen.");
</td>
</tr>
<tr
className="diff-line"
>
<td
className="diff-gutter diff-gutter-normal"
onMouseEnter={[Function]}
onMouseLeave={[Function]}
>
5
</td>
<td
className="diff-gutter diff-gutter-normal"
onMouseEnter={[Function]}
onMouseLeave={[Function]}
>
5
</td>
<td
className="diff-code diff-code-normal"
onMouseEnter={[Function]}
onMouseLeave={[Function]}
>
}
</td>
</tr>
</tbody>
</table>
</div>
</div>,
<div
className="sc-iwsKbI bGoZkF panel is-size-6"
>
<div
className="panel-heading"
>
<div
className="sc-gZMcBi hiXlnL level"
>
<div
className="sc-gqjmRU jMyrLy level-left is-flex has-cursor-pointer"
onClick={[Function]}
title="conflict.png"
>
<span
className="sc-VigVT kUVxiT is-ellipsis-overflow is-size-6"
>
conflict.png
</span>
<span
className="tag is-info is-outlined sc-jzJRlG fdoJSr is-rounded has-text-weight-normal"
>
add
</span>
</div>
<div
className="sc-jTzLTM ljPywG level-right is-flex"
>
<div
className="field is-grouped"
>
<div
className="control"
>
<button
className="button is-default is-reduced-mobile"
onClick={[Function]}
type="button"
>
<span
className="icon is-medium"
>
<i
className="fas fa-columns has-text-inherit"
/>
</span>
<span>
diff.sideBySide
</span>
</button>
</div>
</div>
</div>
</div>
</div>
<div
className="panel-block is-paddingless"
>
<table
className="diff diff-unified sc-cSHVUG cHkPoJ unified"
onMouseDown={[Function]}
>
<colgroup>
<col
className="diff-gutter-col"
/>
<col
className="diff-gutter-col"
/>
<col />
</colgroup>
</table>
</div>
</div>,
]
`;
exports[`Storyshots Diff Collapsed 1`] = ` exports[`Storyshots Diff Collapsed 1`] = `
Array [ Array [
<div <div

View File

@@ -5,6 +5,7 @@ import Diff from "./Diff";
import parser from "gitdiff-parser"; import parser from "gitdiff-parser";
import simpleDiff from "../__resources__/Diff.simple"; import simpleDiff from "../__resources__/Diff.simple";
import hunksDiff from "../__resources__/Diff.hunks"; import hunksDiff from "../__resources__/Diff.hunks";
import binaryDiff from "../__resources__/Diff.binary";
import Button from "../buttons/Button"; import Button from "../buttons/Button";
import { DiffEventContext } from "./DiffTypes"; import { DiffEventContext } from "./DiffTypes";
import Toast from "../toast/Toast"; import Toast from "../toast/Toast";
@@ -52,4 +53,8 @@ storiesOf("Diff", module)
.add("Hunks", () => { .add("Hunks", () => {
const hunkDiffFiles = parser.parse(hunksDiff); const hunkDiffFiles = parser.parse(hunksDiff);
return <Diff diff={hunkDiffFiles} />; return <Diff diff={hunkDiffFiles} />;
})
.add("Binaries", () => {
const binaryDiffFiles = parser.parse(binaryDiff);
return <Diff diff={binaryDiffFiles} />;
}); });

View File

@@ -99,7 +99,7 @@ public class DefaultPluginLoader implements PluginLoader
modules = getInstalled(parent, context, PATH_MODULECONFIG); modules = getInstalled(parent, context, PATH_MODULECONFIG);
collector = new ExtensionCollector(Iterables.concat(modules, unwrap())); collector = new ExtensionCollector(parent, modules, installedPlugins);
extensionProcessor = new DefaultExtensionProcessor(collector); extensionProcessor = new DefaultExtensionProcessor(collector);
} }
catch (IOException | JAXBException ex) catch (IOException | JAXBException ex)
@@ -170,19 +170,6 @@ public class DefaultPluginLoader implements PluginLoader
return uberWebResourceLoader; return uberWebResourceLoader;
} }
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @return
*/
private Iterable<InstalledPluginDescriptor> unwrap()
{
return PluginsInternal.unwrap(installedPlugins);
}
//~--- get methods ---------------------------------------------------------- //~--- get methods ----------------------------------------------------------
/** /**

View File

@@ -98,8 +98,8 @@ public final class ExplodedSmp implements Comparable<ExplodedSmp>
{ {
int result; int result;
Set<String> depends = plugin.getDependencies(); Set<String> depends = plugin.getDependenciesInclusiveOptionals();
Set<String> odepends = o.plugin.getDependencies(); Set<String> odepends = o.plugin.getDependenciesInclusiveOptionals();
if (depends.isEmpty() && odepends.isEmpty()) if (depends.isEmpty() && odepends.isEmpty())
{ {

View File

@@ -55,63 +55,37 @@ import sonia.scm.util.Util;
public final class ExtensionBinder public final class ExtensionBinder
{ {
/** Field description */
private static final String TYPE_LOOSE_EXT = "loose extension"; private static final String TYPE_LOOSE_EXT = "loose extension";
/** Field description */
private static final String TYPE_REST_RESOURCE = "rest resource"; private static final String TYPE_REST_RESOURCE = "rest resource";
private static final String AS_EAGER_SINGLETON = " as eager singleton";
/** /**
* the logger for ExtensionBinder * the logger for ExtensionBinder
*/ */
private static final Logger logger = private static final Logger logger = LoggerFactory.getLogger(ExtensionBinder.class);
LoggerFactory.getLogger(ExtensionBinder.class);
//~--- constructors ---------------------------------------------------------
/**
* Constructs ...
*
*
* @param binder
*/
public ExtensionBinder(Binder binder) public ExtensionBinder(Binder binder)
{ {
this.binder = binder; this.binder = binder;
} }
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param collector
*/
public void bind(ExtensionCollector collector) public void bind(ExtensionCollector collector)
{ {
logger.info("bind extensions to extension points"); logger.debug("bind extensions to extension points");
for (ExtensionPointElement epe : collector.getExtensionPointElements()) for (ExtensionPointElement epe : collector.getExtensionPointElements())
{ {
bindExtensionPoint(collector, epe); bindExtensionPoint(collector, epe);
} }
logger.info("bind loose extensions"); logger.debug("bind loose extensions");
bindLooseExtensions(collector.getLooseExtensions()); bindLooseExtensions(collector.getLooseExtensions());
logger.info("bind rest providers"); logger.debug("bind rest providers");
bindRestProviders(collector.getRestProviders()); bindRestProviders(collector.getRestProviders());
logger.info("bind rest resources"); logger.debug("bind rest resources");
bindRestResource(collector.getRestResources()); bindRestResource(collector.getRestResources());
} }
/**
* Method description
*
*
* @param collector
* @param epe
*/
private void bindExtensionPoint(ExtensionCollector collector, private void bindExtensionPoint(ExtensionCollector collector,
ExtensionPointElement epe) ExtensionPointElement epe)
{ {
@@ -142,12 +116,6 @@ public final class ExtensionBinder
} }
} }
/**
* Method description
*
*
* @param extensions
*/
private void bindLooseExtensions(Iterable<Class> extensions) private void bindLooseExtensions(Iterable<Class> extensions)
{ {
for (Class extension : extensions) for (Class extension : extensions)
@@ -156,46 +124,27 @@ public final class ExtensionBinder
} }
} }
/** private void bindMultiExtensionPoint(ExtensionPointElement extensionPoint, Iterable<Class> extensions)
* Method description
*
*
*
* @param found
*
* @param extensionPoint
*
* @param boundClasses
* @param extensionPointClass
* @param extensions
*/
private void bindMultiExtensionPoint(ExtensionPointElement extensionPoint,
Iterable<Class> extensions)
{ {
Class extensionPointClass = extensionPoint.getClazz(); Class extensionPointClass = extensionPoint.getClazz();
if (logger.isInfoEnabled()) logger.debug("create multibinder for {}", extensionPointClass.getName());
{
logger.info("create multibinder for {}", extensionPointClass.getName());
}
Multibinder multibinder = Multibinder.newSetBinder(binder,
extensionPointClass);
Multibinder multibinder = Multibinder.newSetBinder(binder, extensionPointClass);
for (Class extensionClass : extensions) for (Class extensionClass : extensions)
{ {
boolean eagerSingleton = isEagerSingleton(extensionClass); boolean eagerSingleton = isEagerSingleton(extensionClass);
if (logger.isInfoEnabled()) if (logger.isDebugEnabled())
{ {
String as = Util.EMPTY_STRING; String as = Util.EMPTY_STRING;
if (eagerSingleton) if (eagerSingleton)
{ {
as = " as eager singleton"; as = AS_EAGER_SINGLETON;
} }
logger.info("bind {} to multibinder of {}{}", extensionClass.getName(), logger.debug("bind {} to multibinder of {}{}", extensionClass.getName(),
extensionPointClass.getName(), as); extensionPointClass.getName(), as);
} }
@@ -208,27 +157,15 @@ public final class ExtensionBinder
} }
} }
/**
* Method description
*
*
* @param restProviders
*/
private void bindRestProviders(Iterable<Class> restProviders) private void bindRestProviders(Iterable<Class> restProviders)
{ {
for (Class restProvider : restProviders) for (Class restProvider : restProviders)
{ {
logger.info("bind rest provider {}", restProvider); logger.debug("bind rest provider {}", restProvider);
binder.bind(restProvider).in(Singleton.class); binder.bind(restProvider).in(Singleton.class);
} }
} }
/**
* Method description
*
*
* @param restResources
*/
private void bindRestResource(Iterable<Class> restResources) private void bindRestResource(Iterable<Class> restResources)
{ {
for (Class restResource : restResources) for (Class restResource : restResources)
@@ -237,31 +174,22 @@ public final class ExtensionBinder
} }
} }
/**
* Method description
*
*
* @param extensionPointClass
*
* @param extensionPoint
* @param extensionClass
*/
private void bindSingleInstance(ExtensionPointElement extensionPoint, private void bindSingleInstance(ExtensionPointElement extensionPoint,
Class extensionClass) Class extensionClass)
{ {
Class extensionPointClass = extensionPoint.getClazz(); Class extensionPointClass = extensionPoint.getClazz();
boolean eagerSingleton = isEagerSingleton(extensionClass); boolean eagerSingleton = isEagerSingleton(extensionClass);
if (logger.isInfoEnabled()) if (logger.isDebugEnabled())
{ {
String as = Util.EMPTY_STRING; String as = Util.EMPTY_STRING;
if (eagerSingleton) if (eagerSingleton)
{ {
as = " as eager singleton"; as = AS_EAGER_SINGLETON;
} }
logger.info("bind {} to {}{}", extensionClass.getName(), logger.debug("bind {} to {}{}", extensionClass.getName(),
extensionPointClass.getName(), as); extensionPointClass.getName(), as);
} }
@@ -274,13 +202,6 @@ public final class ExtensionBinder
} }
} }
/**
* Method description
*
*
* @param type
* @param extension
*/
private void singleBind(String type, Class extension) private void singleBind(String type, Class extension)
{ {
StringBuilder log = new StringBuilder(); StringBuilder log = new StringBuilder();
@@ -291,30 +212,19 @@ public final class ExtensionBinder
if (isEagerSingleton(extension)) if (isEagerSingleton(extension))
{ {
log.append(" as eager singleton"); log.append(AS_EAGER_SINGLETON);
abb.asEagerSingleton(); abb.asEagerSingleton();
} }
logger.info(log.toString()); if (logger.isDebugEnabled()) {
logger.debug(log.toString());
}
} }
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @param extensionClass
*
* @return
*/
private boolean isEagerSingleton(Class extensionClass) private boolean isEagerSingleton(Class extensionClass)
{ {
return extensionClass.isAnnotationPresent(EagerSingleton.class); return extensionClass.isAnnotationPresent(EagerSingleton.class);
} }
//~--- fields ---------------------------------------------------------------
/** Field description */
private final Binder binder; private final Binder binder;
} }

View File

@@ -39,6 +39,8 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
//~--- JDK imports ------------------------------------------------------------ //~--- JDK imports ------------------------------------------------------------
@@ -47,6 +49,7 @@ import java.util.Collections;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
/** /**
* *
@@ -56,23 +59,33 @@ import java.util.Set;
public final class ExtensionCollector public final class ExtensionCollector
{ {
/** private static final Logger LOG = LoggerFactory.getLogger(ExtensionCollector.class);
* Constructs ...
* private final Set<String> pluginIndex;
*
* @param modules public ExtensionCollector(ClassLoader moduleClassLoader, Set<ScmModule> modules, Set<InstalledPlugin> installedPlugins) {
*/ this.pluginIndex = createPluginIndex(installedPlugins);
ExtensionCollector(Iterable<ScmModule> modules)
{ for (ScmModule module : modules) {
for (ScmModule module : modules)
{
collectRootElements(module); collectRootElements(module);
} }
for (ScmModule plugin : PluginsInternal.unwrap(installedPlugins)) {
for (ScmModule module : modules) collectRootElements(plugin);
{
collectExtensions(module);
} }
for (ScmModule module : modules) {
collectExtensions(moduleClassLoader, module);
}
for (InstalledPlugin plugin : installedPlugins) {
collectExtensions(plugin.getClassLoader(), plugin.getDescriptor());
}
}
private Set<String> createPluginIndex(Set<InstalledPlugin> installedPlugins) {
return installedPlugins.stream()
.map(p -> p.getDescriptor().getInformation().getName())
.collect(Collectors.toSet());
} }
//~--- methods -------------------------------------------------------------- //~--- methods --------------------------------------------------------------
@@ -245,20 +258,35 @@ public final class ExtensionCollector
} }
} }
/** private void collectExtensions(ClassLoader defaultClassLoader, ScmModule module) {
* Method description for (ExtensionElement extension : module.getExtensions()) {
* if (isRequirementFulfilled(extension)) {
* Class<?> extensionClass = loadExtension(defaultClassLoader, extension);
* @param module appendExtension(extensionClass);
*/ }
private void collectExtensions(ScmModule module)
{
for (Class extension : module.getExtensions())
{
appendExtension(extension);
} }
} }
private Class<?> loadExtension(ClassLoader classLoader, ExtensionElement extension) {
try {
return classLoader.loadClass(extension.getClazz());
} catch (ClassNotFoundException ex) {
throw new PluginLoadException("failed to load clazz", ex);
}
}
private boolean isRequirementFulfilled(ExtensionElement extension) {
if (extension.getRequires() != null) {
for (String requiredPlugin : extension.getRequires()) {
if (!pluginIndex.contains(requiredPlugin)) {
LOG.debug("skip loading of extension {}, because the required plugin {} is not installed", extension.getClazz(), requiredPlugin);
return false;
}
}
}
return true;
}
/** /**
* Method description * Method description
* *

View File

@@ -189,7 +189,7 @@ public final class PluginProcessor
PluginTree pluginTree = new PluginTree(smps); PluginTree pluginTree = new PluginTree(smps);
logger.trace("build plugin tree: {}", pluginTree); logger.info("install plugin tree:\n{}", pluginTree);
List<PluginNode> rootNodes = pluginTree.getRootNodes(); List<PluginNode> rootNodes = pluginTree.getRootNodes();

View File

@@ -35,15 +35,13 @@ package sonia.scm.plugin;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Ordering; import com.google.common.collect.Ordering;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
//~--- JDK imports ------------------------------------------------------------
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Set;
//~--- JDK imports ------------------------------------------------------------
/** /**
* *
@@ -104,9 +102,7 @@ public final class PluginTree
if ((condition == null) || condition.isSupported()) if ((condition == null) || condition.isSupported())
{ {
Set<String> dependencies = plugin.getDependencies(); if (plugin.getDependencies().isEmpty() && plugin.getOptionalDependencies().isEmpty())
if ((dependencies == null) || dependencies.isEmpty())
{ {
rootNodes.add(new PluginNode(smp)); rootNodes.add(new PluginNode(smp));
} }
@@ -170,6 +166,20 @@ public final class PluginTree
//J+ //J+
} }
} }
boolean rootNode = smp.getPlugin().getDependencies().isEmpty();
for (String dependency : smp.getPlugin().getOptionalDependencies()) {
if (appendNode(rootNodes, child, dependency)) {
rootNode = false;
} else {
logger.info("optional dependency {} of {} is not installed", dependency, child.getId());
}
}
if (rootNode) {
logger.info("could not find optional dependencies of {}, append it as root node", child.getId());
rootNodes.add(new PluginNode(smp));
}
} }
/** /**
@@ -212,7 +222,18 @@ public final class PluginTree
@Override @Override
public String toString() { public String toString() {
return "plugin tree: " + rootNodes.toString(); StringBuilder buffer = new StringBuilder();
for (PluginNode node : rootNodes) {
append(buffer, "", node);
}
return buffer.toString();
}
private void append(StringBuilder buffer, String indent, PluginNode node) {
buffer.append(indent).append("+- ").append(node.getId()).append("\n");
for (PluginNode child : node.getChildren()) {
append(buffer, indent + " ", child);
}
} }
//~--- fields --------------------------------------------------------------- //~--- fields ---------------------------------------------------------------

View File

@@ -134,7 +134,7 @@ public class ExplodedSmpTest
info.setVersion(version); info.setVersion(version);
InstalledPluginDescriptor plugin = new InstalledPluginDescriptor(2, info, null, null, false, InstalledPluginDescriptor plugin = new InstalledPluginDescriptor(2, info, null, null, false,
Sets.newSet(dependencies)); Sets.newSet(dependencies), null);
return new ExplodedSmp(null, plugin); return new ExplodedSmp(null, plugin);
} }

View File

@@ -34,6 +34,7 @@ package sonia.scm.plugin;
//~--- non-JDK imports -------------------------------------------------------- //~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import org.junit.Rule; import org.junit.Rule;
@@ -72,7 +73,7 @@ public class PluginTreeTest
PluginCondition condition = new PluginCondition("999", PluginCondition condition = new PluginCondition("999",
new ArrayList<String>(), "hit"); new ArrayList<String>(), "hit");
InstalledPluginDescriptor plugin = new InstalledPluginDescriptor(2, createInfo("a", "1"), null, condition, InstalledPluginDescriptor plugin = new InstalledPluginDescriptor(2, createInfo("a", "1"), null, condition,
false, null); false, null, null);
ExplodedSmp smp = createSmp(plugin); ExplodedSmp smp = createSmp(plugin);
new PluginTree(smp).getRootNodes(); new PluginTree(smp).getRootNodes();
@@ -115,7 +116,7 @@ public class PluginTreeTest
public void testScmVersion() throws IOException public void testScmVersion() throws IOException
{ {
InstalledPluginDescriptor plugin = new InstalledPluginDescriptor(1, createInfo("a", "1"), null, null, false, InstalledPluginDescriptor plugin = new InstalledPluginDescriptor(1, createInfo("a", "1"), null, null, false,
null); null, null);
ExplodedSmp smp = createSmp(plugin); ExplodedSmp smp = createSmp(plugin);
new PluginTree(smp).getRootNodes(); new PluginTree(smp).getRootNodes();
@@ -131,10 +132,10 @@ public class PluginTreeTest
public void testSimpleDependencies() throws IOException public void testSimpleDependencies() throws IOException
{ {
//J- //J-
ExplodedSmp[] smps = new ExplodedSmp[] { ExplodedSmp[] smps = new ExplodedSmp[] {
createSmpWithDependency("a"), createSmpWithDependency("a"),
createSmpWithDependency("b", "a"), createSmpWithDependency("b", "a"),
createSmpWithDependency("c", "a", "b") createSmpWithDependency("c", "a", "b")
}; };
//J+ //J+
@@ -152,6 +153,61 @@ public class PluginTreeTest
assertThat(unwrapIds(b.getChildren()), containsInAnyOrder("c")); assertThat(unwrapIds(b.getChildren()), containsInAnyOrder("c"));
} }
@Test
public void testWithOptionalDependency() throws IOException {
ExplodedSmp[] smps = new ExplodedSmp[] {
createSmpWithDependency("a"),
createSmpWithDependency("b", null, ImmutableSet.of("a")),
createSmpWithDependency("c", null, ImmutableSet.of("a", "b"))
};
PluginTree tree = new PluginTree(smps);
List<PluginNode> rootNodes = tree.getRootNodes();
assertThat(unwrapIds(rootNodes), containsInAnyOrder("a"));
PluginNode a = rootNodes.get(0);
assertThat(unwrapIds(a.getChildren()), containsInAnyOrder("b", "c"));
PluginNode b = a.getChild("b");
assertThat(unwrapIds(b.getChildren()), containsInAnyOrder("c"));
}
@Test
public void testWithDeepOptionalDependency() throws IOException {
ExplodedSmp[] smps = new ExplodedSmp[] {
createSmpWithDependency("a"),
createSmpWithDependency("b", "a"),
createSmpWithDependency("c", null, ImmutableSet.of("b"))
};
PluginTree tree = new PluginTree(smps);
System.out.println(tree);
List<PluginNode> rootNodes = tree.getRootNodes();
assertThat(unwrapIds(rootNodes), containsInAnyOrder("a"));
PluginNode a = rootNodes.get(0);
assertThat(unwrapIds(a.getChildren()), containsInAnyOrder("b"));
PluginNode b = a.getChild("b");
assertThat(unwrapIds(b.getChildren()), containsInAnyOrder("c"));
}
@Test
public void testWithNonExistentOptionalDependency() throws IOException {
ExplodedSmp[] smps = new ExplodedSmp[] {
createSmpWithDependency("a", null, ImmutableSet.of("b"))
};
PluginTree tree = new PluginTree(smps);
List<PluginNode> rootNodes = tree.getRootNodes();
assertThat(unwrapIds(rootNodes), containsInAnyOrder("a"));
}
/** /**
* Method description * Method description
* *
@@ -200,7 +256,7 @@ public class PluginTreeTest
private ExplodedSmp createSmp(String name) throws IOException private ExplodedSmp createSmp(String name) throws IOException
{ {
return createSmp(new InstalledPluginDescriptor(2, createInfo(name, "1.0.0"), null, null, return createSmp(new InstalledPluginDescriptor(2, createInfo(name, "1.0.0"), null, null,
false, null)); false, null, null));
} }
/** /**
@@ -224,10 +280,19 @@ public class PluginTreeTest
{ {
dependencySet.add(d); dependencySet.add(d);
} }
return createSmpWithDependency(name, dependencySet, null);
}
InstalledPluginDescriptor plugin = new InstalledPluginDescriptor(2, createInfo(name, "1"), null, null, private ExplodedSmp createSmpWithDependency(String name, Set<String> dependencies, Set<String> optionalDependencies) throws IOException {
false, dependencySet); InstalledPluginDescriptor plugin = new InstalledPluginDescriptor(
2,
createInfo(name, "1"),
null,
null,
false,
dependencies,
optionalDependencies
);
return createSmp(plugin); return createSmp(plugin);
} }

View File

@@ -7332,9 +7332,9 @@ gitconfiglocal@^1.0.0:
dependencies: dependencies:
ini "^1.3.2" ini "^1.3.2"
gitdiff-parser@^0.1.2, "gitdiff-parser@https://github.com/scm-manager/gitdiff-parser#6baa7278824ecd17a199d842ca720d0453f68982": gitdiff-parser@^0.1.2, "gitdiff-parser@https://github.com/scm-manager/gitdiff-parser#ed3fe7de73dbb0a06c3e6adbbdf22dbae6e66351":
version "0.1.2" version "0.1.2"
resolved "https://github.com/scm-manager/gitdiff-parser#6baa7278824ecd17a199d842ca720d0453f68982" resolved "https://github.com/scm-manager/gitdiff-parser#ed3fe7de73dbb0a06c3e6adbbdf22dbae6e66351"
glob-parent@^3.1.0: glob-parent@^3.1.0:
version "3.1.0" version "3.1.0"