blob: 8b668ddd95a57998c26b6e96b205890419411e12 [file] [log] [blame]
Stuart McCulloch233a5742009-02-16 07:36:22 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19package org.apache.felix.bundleplugin;
20
21
22import java.util.Collection;
Stuart McCulloch233a5742009-02-16 07:36:22 +000023import java.util.Iterator;
Stuart McCulloch271f1732011-10-26 23:12:36 +000024import java.util.LinkedHashSet;
Guillaume Nodeted7b1102015-07-09 19:45:09 +000025import java.util.List;
Stuart McCulloch233a5742009-02-16 07:36:22 +000026import java.util.Map;
Guillaume Nodeted7b1102015-07-09 19:45:09 +000027import java.util.Set;
Stuart McCulloche78eff92011-10-26 21:54:03 +000028import java.util.regex.Pattern;
Stuart McCulloch233a5742009-02-16 07:36:22 +000029
30import org.apache.maven.artifact.Artifact;
Guillaume Nodeted7b1102015-07-09 19:45:09 +000031import org.apache.maven.artifact.resolver.filter.AndArtifactFilter;
32import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
Stuart McCulloch233a5742009-02-16 07:36:22 +000033import org.apache.maven.plugin.MojoExecutionException;
34
Carsten Ziegeler82d87402015-03-04 13:26:21 +000035import aQute.bnd.header.Attrs;
Stuart McCulloch42151ee2012-07-16 13:43:38 +000036import aQute.bnd.header.OSGiHeader;
Carsten Ziegeler82d87402015-03-04 13:26:21 +000037import aQute.bnd.osgi.Instruction;
Guillaume Nodeted7b1102015-07-09 19:45:09 +000038import org.apache.maven.shared.dependency.graph.DependencyNode;
39import org.apache.maven.shared.dependency.graph.filter.ArtifactDependencyNodeFilter;
40import org.apache.maven.shared.dependency.graph.filter.DependencyNodeFilter;
41import org.apache.maven.shared.dependency.graph.traversal.BuildingDependencyNodeVisitor;
42import org.apache.maven.shared.dependency.graph.traversal.CollectingDependencyNodeVisitor;
43import org.apache.maven.shared.dependency.graph.traversal.DependencyNodeVisitor;
44import org.apache.maven.shared.dependency.graph.traversal.FilteringDependencyNodeVisitor;
Stuart McCulloch233a5742009-02-16 07:36:22 +000045
46
47/**
48 * Apply clause-based filter over given dependencies
Carsten Ziegeler82d87402015-03-04 13:26:21 +000049 *
Richard S. Hall3bc8afd2009-08-12 19:03:19 +000050 * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
Stuart McCulloch233a5742009-02-16 07:36:22 +000051 */
52public abstract class AbstractDependencyFilter
53{
Stuart McCulloch271f1732011-10-26 23:12:36 +000054 private static final Pattern MISSING_KEY_PATTERN = Pattern.compile( "(^|,)\\p{Blank}*(!)?\\p{Blank}*([a-zA-Z]+=)" );
Stuart McCulloche78eff92011-10-26 21:54:03 +000055
Stuart McCulloch233a5742009-02-16 07:36:22 +000056 /**
Guillaume Nodeted7b1102015-07-09 19:45:09 +000057 * Dependency Graph.
58 */
59 private final DependencyNode m_dependencyGraph;
60 /**
Stuart McCulloch233a5742009-02-16 07:36:22 +000061 * Dependency artifacts.
62 */
Carsten Ziegeler82d87402015-03-04 13:26:21 +000063 private final Collection<Artifact> m_dependencyArtifacts;
Stuart McCulloch233a5742009-02-16 07:36:22 +000064
65
Guillaume Nodeted7b1102015-07-09 19:45:09 +000066 public AbstractDependencyFilter( DependencyNode dependencyGraph, Collection<Artifact> dependencyArtifacts )
Stuart McCulloch233a5742009-02-16 07:36:22 +000067 {
Guillaume Nodeted7b1102015-07-09 19:45:09 +000068 m_dependencyGraph = dependencyGraph;
Stuart McCulloch233a5742009-02-16 07:36:22 +000069 m_dependencyArtifacts = dependencyArtifacts;
70 }
71
Guillaume Nodeted7b1102015-07-09 19:45:09 +000072 private static abstract class DependencyFilter implements ArtifactFilter
Stuart McCulloch233a5742009-02-16 07:36:22 +000073 {
74 private final Instruction m_instruction;
75 private final String m_defaultValue;
76
77
78 public DependencyFilter( String expression )
79 {
80 this( expression, "" );
81 }
82
83
84 public DependencyFilter( String expression, String defaultValue )
85 {
Stuart McCullochf3173222012-06-07 21:57:32 +000086 m_instruction = new Instruction( expression );
Stuart McCulloch233a5742009-02-16 07:36:22 +000087 m_defaultValue = defaultValue;
88 }
89
Guillaume Nodeted7b1102015-07-09 19:45:09 +000090 public abstract boolean include( Artifact dependency );
Stuart McCulloch233a5742009-02-16 07:36:22 +000091
92 boolean matches( String text )
93 {
94 boolean result;
95
96 if ( null == text )
97 {
98 result = m_instruction.matches( m_defaultValue );
99 }
100 else
101 {
102 result = m_instruction.matches( text );
103 }
104
105 return m_instruction.isNegated() ? !result : result;
106 }
107 }
108
Guillaume Nodeted7b1102015-07-09 19:45:09 +0000109 private static class TrimmingDependencyNodeFilter implements DependencyNodeFilter
110 {
111 private DependencyNodeFilter dependencyNodeFilter;
112
113 public TrimmingDependencyNodeFilter( DependencyNodeFilter dependencyNodeFilter )
114 {
115 this.dependencyNodeFilter = dependencyNodeFilter;
116 }
117
118 public boolean accept( DependencyNode node )
119 {
120 boolean accepted = dependencyNodeFilter.accept( node );
121 if( !accepted )
122 {
123 List<DependencyNode> children = node.getChildren();
124 children.clear();
125 }
126 return accepted;
127 }
128 }
Stuart McCulloch233a5742009-02-16 07:36:22 +0000129
Stuart McCulloche78eff92011-10-26 21:54:03 +0000130 protected final void processInstructions( String header ) throws MojoExecutionException
Stuart McCulloch233a5742009-02-16 07:36:22 +0000131 {
Carsten Ziegeler82d87402015-03-04 13:26:21 +0000132 Map<String,Attrs> instructions = OSGiHeader.parseHeader( MISSING_KEY_PATTERN.matcher( header ).replaceAll( "$1$2*;$3" ) );
Stuart McCulloch271f1732011-10-26 23:12:36 +0000133
Carsten Ziegeler82d87402015-03-04 13:26:21 +0000134 Collection<Artifact> availableDependencies = new LinkedHashSet<Artifact>( m_dependencyArtifacts );
Stuart McCulloche78eff92011-10-26 21:54:03 +0000135
Carsten Ziegeler82d87402015-03-04 13:26:21 +0000136 for ( Iterator<Map.Entry<String,Attrs>> clauseIterator = instructions.entrySet().iterator(); clauseIterator.hasNext(); )
Stuart McCulloch233a5742009-02-16 07:36:22 +0000137 {
138 String inline = "false";
139
Stuart McCulloch271f1732011-10-26 23:12:36 +0000140 // always start with a fresh *modifiable* collection for each unique clause
Carsten Ziegeler82d87402015-03-04 13:26:21 +0000141 Collection<Artifact> filteredDependencies = new LinkedHashSet<Artifact>( availableDependencies );
Stuart McCulloch233a5742009-02-16 07:36:22 +0000142
143 // CLAUSE: REGEXP --> { ATTRIBUTE MAP }
Carsten Ziegeler82d87402015-03-04 13:26:21 +0000144 Map.Entry<String,Attrs> clause = clauseIterator.next();
145 String primaryKey = clause.getKey().replaceFirst( "~+$", "" );
Stuart McCulloch271f1732011-10-26 23:12:36 +0000146 boolean isNegative = primaryKey.startsWith( "!" );
147 if ( isNegative )
148 {
149 primaryKey = primaryKey.substring( 1 );
150 }
151
Guillaume Nodeted7b1102015-07-09 19:45:09 +0000152 final AndArtifactFilter andArtifactFilter = new AndArtifactFilter();
Stuart McCulloche8851a52011-10-26 21:14:28 +0000153 if ( !"*".equals( primaryKey ) )
Stuart McCullochd98b02e2011-06-28 23:20:37 +0000154 {
Guillaume Nodeted7b1102015-07-09 19:45:09 +0000155 ArtifactFilter filter = new DependencyFilter( primaryKey )
Stuart McCulloch233a5742009-02-16 07:36:22 +0000156 {
Carsten Ziegeler82d87402015-03-04 13:26:21 +0000157 @Override
Guillaume Nodeted7b1102015-07-09 19:45:09 +0000158 public boolean include( Artifact dependency )
Hiram R. Chirino20a916a2011-01-29 01:39:54 +0000159 {
160 return super.matches( dependency.getArtifactId() );
161 }
162 };
163 // FILTER ON MAIN CLAUSE
Guillaume Nodeted7b1102015-07-09 19:45:09 +0000164 andArtifactFilter.add(filter);
Hiram R. Chirino20a916a2011-01-29 01:39:54 +0000165 }
Stuart McCulloch233a5742009-02-16 07:36:22 +0000166
Carsten Ziegeler82d87402015-03-04 13:26:21 +0000167 for ( Iterator<Map.Entry<String,String>> attrIterator = clause.getValue().entrySet().iterator(); attrIterator.hasNext(); )
Stuart McCulloch233a5742009-02-16 07:36:22 +0000168 {
Guillaume Nodeted7b1102015-07-09 19:45:09 +0000169 final ArtifactFilter filter;
Stuart McCulloch233a5742009-02-16 07:36:22 +0000170 // ATTRIBUTE: KEY --> REGEXP
Carsten Ziegeler82d87402015-03-04 13:26:21 +0000171 Map.Entry<String,String> attr = attrIterator.next();
Stuart McCulloch233a5742009-02-16 07:36:22 +0000172 if ( "groupId".equals( attr.getKey() ) )
173 {
Carsten Ziegeler82d87402015-03-04 13:26:21 +0000174 filter = new DependencyFilter( attr.getValue() )
Stuart McCulloch233a5742009-02-16 07:36:22 +0000175 {
Carsten Ziegeler82d87402015-03-04 13:26:21 +0000176 @Override
Guillaume Nodeted7b1102015-07-09 19:45:09 +0000177 public boolean include( Artifact dependency )
Stuart McCulloch233a5742009-02-16 07:36:22 +0000178 {
179 return super.matches( dependency.getGroupId() );
180 }
181 };
182 }
183 else if ( "artifactId".equals( attr.getKey() ) )
184 {
Carsten Ziegeler82d87402015-03-04 13:26:21 +0000185 filter = new DependencyFilter( attr.getValue() )
Stuart McCulloch233a5742009-02-16 07:36:22 +0000186 {
Carsten Ziegeler82d87402015-03-04 13:26:21 +0000187 @Override
Guillaume Nodeted7b1102015-07-09 19:45:09 +0000188 public boolean include( Artifact dependency )
Stuart McCulloch233a5742009-02-16 07:36:22 +0000189 {
190 return super.matches( dependency.getArtifactId() );
191 }
192 };
193 }
194 else if ( "version".equals( attr.getKey() ) )
195 {
Carsten Ziegeler82d87402015-03-04 13:26:21 +0000196 filter = new DependencyFilter( attr.getValue() )
Stuart McCulloch233a5742009-02-16 07:36:22 +0000197 {
Carsten Ziegeler82d87402015-03-04 13:26:21 +0000198 @Override
Guillaume Nodeted7b1102015-07-09 19:45:09 +0000199 public boolean include( Artifact dependency )
Stuart McCulloch233a5742009-02-16 07:36:22 +0000200 {
201 try
202 {
203 // use the symbolic version if available (ie. 1.0.0-SNAPSHOT)
204 return super.matches( dependency.getSelectedVersion().toString() );
205 }
206 catch ( Exception e )
207 {
208 return super.matches( dependency.getVersion() );
209 }
210 }
211 };
212 }
213 else if ( "scope".equals( attr.getKey() ) )
214 {
Carsten Ziegeler82d87402015-03-04 13:26:21 +0000215 filter = new DependencyFilter( attr.getValue(), "compile" )
Stuart McCulloch233a5742009-02-16 07:36:22 +0000216 {
Carsten Ziegeler82d87402015-03-04 13:26:21 +0000217 @Override
Guillaume Nodeted7b1102015-07-09 19:45:09 +0000218 public boolean include( Artifact dependency )
Stuart McCulloch233a5742009-02-16 07:36:22 +0000219 {
220 return super.matches( dependency.getScope() );
221 }
222 };
223 }
224 else if ( "type".equals( attr.getKey() ) )
225 {
Carsten Ziegeler82d87402015-03-04 13:26:21 +0000226 filter = new DependencyFilter( attr.getValue(), "jar" )
Stuart McCulloch233a5742009-02-16 07:36:22 +0000227 {
Carsten Ziegeler82d87402015-03-04 13:26:21 +0000228 @Override
Guillaume Nodeted7b1102015-07-09 19:45:09 +0000229 public boolean include( Artifact dependency )
Stuart McCulloch233a5742009-02-16 07:36:22 +0000230 {
231 return super.matches( dependency.getType() );
232 }
233 };
234 }
235 else if ( "classifier".equals( attr.getKey() ) )
236 {
Carsten Ziegeler82d87402015-03-04 13:26:21 +0000237 filter = new DependencyFilter( attr.getValue() )
Stuart McCulloch233a5742009-02-16 07:36:22 +0000238 {
Carsten Ziegeler82d87402015-03-04 13:26:21 +0000239 @Override
Guillaume Nodeted7b1102015-07-09 19:45:09 +0000240 public boolean include( Artifact dependency )
Stuart McCulloch233a5742009-02-16 07:36:22 +0000241 {
242 return super.matches( dependency.getClassifier() );
243 }
244 };
245 }
246 else if ( "optional".equals( attr.getKey() ) )
247 {
Carsten Ziegeler82d87402015-03-04 13:26:21 +0000248 filter = new DependencyFilter( attr.getValue(), "false" )
Stuart McCulloch233a5742009-02-16 07:36:22 +0000249 {
Carsten Ziegeler82d87402015-03-04 13:26:21 +0000250 @Override
Guillaume Nodeted7b1102015-07-09 19:45:09 +0000251 public boolean include( Artifact dependency )
Stuart McCulloch233a5742009-02-16 07:36:22 +0000252 {
253 return super.matches( "" + dependency.isOptional() );
254 }
255 };
256 }
257 else if ( "inline".equals( attr.getKey() ) )
258 {
Carsten Ziegeler82d87402015-03-04 13:26:21 +0000259 inline = attr.getValue();
Stuart McCulloch233a5742009-02-16 07:36:22 +0000260 continue;
261 }
262 else
263 {
264 throw new MojoExecutionException( "Unexpected attribute " + attr.getKey() );
265 }
266
267 // FILTER ON EACH ATTRIBUTE
Guillaume Nodeted7b1102015-07-09 19:45:09 +0000268 andArtifactFilter.add( filter );
Stuart McCulloch233a5742009-02-16 07:36:22 +0000269 }
270
Guillaume Nodeted7b1102015-07-09 19:45:09 +0000271 filteredDependencies( andArtifactFilter, filteredDependencies );
272
Stuart McCulloch271f1732011-10-26 23:12:36 +0000273 if ( isNegative )
274 {
275 // negative clauses reduce the set of available artifacts
276 availableDependencies.removeAll( filteredDependencies );
277 if ( !clauseIterator.hasNext() )
278 {
279 // assume there's an implicit * missing at the end
280 processDependencies( availableDependencies, inline );
281 }
282 }
283 else
284 {
285 // positive clause; doesn't alter the available artifacts
286 processDependencies( filteredDependencies, inline );
287 }
Stuart McCulloch233a5742009-02-16 07:36:22 +0000288 }
289 }
290
291
Carsten Ziegeler82d87402015-03-04 13:26:21 +0000292 protected abstract void processDependencies( Collection<Artifact> dependencies, String inline );
Guillaume Nodeted7b1102015-07-09 19:45:09 +0000293
294 private void filteredDependencies( final ArtifactFilter artifactFilter, Collection<Artifact> filteredDependencies )
295 {
296 CollectingDependencyNodeVisitor collectingDependencyNodeVisitor = new CollectingDependencyNodeVisitor();
297 final Artifact rootArtifact = m_dependencyGraph.getArtifact();
298 ArtifactFilter filter = new ArtifactFilter()
299 {
300
301
302 public boolean include( Artifact artifact )
303 {
304 return artifact.equals( rootArtifact ) || artifactFilter.include( artifact );
305 }
306
307
308 };
309 DependencyNodeFilter dependencyNodeFilter = new ArtifactDependencyNodeFilter( filter );
310 dependencyNodeFilter = new TrimmingDependencyNodeFilter( dependencyNodeFilter );
311 DependencyNodeVisitor dependencyNodeVisitor =
312 new FilteringDependencyNodeVisitor( collectingDependencyNodeVisitor, dependencyNodeFilter );
313 dependencyNodeVisitor = new BuildingDependencyNodeVisitor( dependencyNodeVisitor );
314 m_dependencyGraph.accept( dependencyNodeVisitor );
315 List<DependencyNode> dependencyNodes = collectingDependencyNodeVisitor.getNodes();
316 Set<String> ids = new LinkedHashSet<String>( dependencyNodes.size() );
317 for( DependencyNode dependencyNode : dependencyNodes ) {
318 Artifact artifact = dependencyNode.getArtifact();
319 String id = artifact.getId();
320 ids.add(id);
321 }
322 for (Iterator<Artifact> iterator = filteredDependencies.iterator(); iterator.hasNext();)
323 {
324 Artifact artifact = iterator.next();
325 String id = artifact.getId();
326 if (!ids.contains(id))
327 {
328 iterator.remove();
329 }
330 }
331 }
Stuart McCulloch233a5742009-02-16 07:36:22 +0000332}