Rework SingleFeatureTest
[odlparent.git] / features-test-plugin / src / main / java / org / opendaylight / odlparent / features / test / plugin / DependencyUtils.java
1 /*
2  * Copyright (c) 2024 PANTHEON.tech s.r.o. and others. All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.odlparent.features.test.plugin;
9
10 import java.io.IOException;
11 import java.net.MalformedURLException;
12 import java.util.Collection;
13 import java.util.LinkedHashSet;
14 import java.util.LinkedList;
15 import java.util.List;
16 import java.util.Properties;
17 import org.apache.karaf.features.BundleInfo;
18 import org.apache.karaf.features.internal.model.Bundle;
19 import org.apache.karaf.features.internal.model.ConfigFile;
20 import org.apache.karaf.features.internal.model.Features;
21 import org.apache.karaf.util.maven.Parser;
22 import org.eclipse.aether.artifact.Artifact;
23 import org.eclipse.aether.artifact.DefaultArtifact;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 /**
28  * Utility artifact responsible for maven dependencies extraction and conversion.
29  */
30 final class DependencyUtils {
31     private static final Logger LOG = LoggerFactory.getLogger(DependencyUtils.class);
32     private static final String MVN_PREFIX = "mvn:";
33     private static final int MVN_CUT_INDEX = MVN_PREFIX.length();
34     private static final String WRAP_PREFIX = "wrap:mvn:";
35     private static final int WRAP_CUT_INDEX = WRAP_PREFIX.length();
36
37     static final String XML = "xml";
38     static final String TEST = "test";
39     static final String FEATURES = "features";
40
41     static final String RELEASE_VERSION;
42     static final String KARAF_VERSION;
43     static final String PAX_EXAM_VERSION;
44
45     static {
46         try (var in = DependencyUtils.class.getClassLoader().getResourceAsStream("versions")) {
47             if (in == null) {
48                 throw new ExceptionInInitializerError("Cannot read from 'versions' resource");
49             }
50             final var props = new Properties();
51             props.load(in);
52             RELEASE_VERSION = nonnullValue(props, "release.version");
53             KARAF_VERSION = nonnullValue(props, "karaf.version");
54             PAX_EXAM_VERSION = nonnullValue(props, "pax.exam.version");
55         } catch (IOException | IllegalStateException e) {
56             throw new ExceptionInInitializerError(e);
57         }
58     }
59
60     private DependencyUtils() {
61         // utility class
62     }
63
64     static Collection<Artifact> extractDependencies(final Features features) {
65         final var urls = new LinkedHashSet<String>();
66         urls.addAll(features.getRepository());
67         for (var feature : features.getFeature()) {
68             if (feature.getBundle() != null) {
69                 urls.addAll(feature.getBundle().stream().map(Bundle::getLocation).toList());
70             }
71             if (feature.getConditional() != null) {
72                 urls.addAll(feature.getConditional().stream()
73                     .filter(conditional -> conditional.getBundles() != null)
74                     .flatMap(conditional -> conditional.getBundles().stream())
75                     .map(BundleInfo::getLocation).toList());
76             }
77             if (feature.getConfigfile() != null) {
78                 urls.addAll(feature.getConfigfile().stream().map(ConfigFile::getLocation).toList());
79             }
80         }
81         final var artifacts = new LinkedList<Artifact>();
82         urls.forEach(url -> collectArtifact(url, artifacts));
83         return artifacts;
84     }
85
86     private static void collectArtifact(final String url, final Collection<Artifact> collection) {
87         final var filteredUrl = url == null ? null : filterMvnUrl(url);
88         if (filteredUrl != null) {
89             final Parser parser;
90             try {
91                 parser = new Parser(filteredUrl);
92             } catch (MalformedURLException e) {
93                 LOG.warn("Error parsing url {} -> dependency omitted", url, e);
94                 return;
95             }
96             collection.add(new DefaultArtifact(parser.getGroup(), parser.getArtifact(),
97                 parser.getClassifier(), parser.getType(), parser.getVersion()));
98         }
99     }
100
101     private static String filterMvnUrl(final String url) {
102         if (url.startsWith(MVN_PREFIX)) {
103             return url.substring(MVN_CUT_INDEX);
104         }
105         if (url.startsWith(WRAP_PREFIX)) {
106             final var endIndex = url.indexOf('$');
107             return endIndex > WRAP_CUT_INDEX ? url.substring(WRAP_CUT_INDEX, endIndex) : url.substring(WRAP_CUT_INDEX);
108         }
109         return null;
110     }
111
112     static Artifact toAetherArtifact(final org.apache.maven.artifact.Artifact mavenArtifact) {
113         return new DefaultArtifact(mavenArtifact.getGroupId(), mavenArtifact.getArtifactId(),
114             mavenArtifact.getClassifier(), mavenArtifact.getType(), mavenArtifact.getVersion());
115     }
116
117     static String identifierOf(final Artifact artifact) {
118         return String.join(":", List.of(artifact.getGroupId(), artifact.getArtifactId(),
119             artifact.getVersion(), artifact.getClassifier(), artifact.getExtension()));
120     }
121
122     static boolean isFeature(final Artifact artifact) {
123         return FEATURES.equals(artifact.getClassifier()) && XML.equals(artifact.getExtension());
124     }
125
126     private static String nonnullValue(final Properties props, final String key) {
127         final var value = props.getProperty(key);
128         if (value == null) {
129             throw new IllegalStateException("no property value found for key " + key);
130         }
131         return value;
132     }
133 }