Skip to content

Commit 2245ab7

Browse files
committed
feat: added SMO search backends
Fixes #64
1 parent 6bc4008 commit 2245ab7

File tree

8 files changed

+214
-43
lines changed

8 files changed

+214
-43
lines changed

app.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
dependencies:
22
eu.maveniverse.maven.mima:context: "2.4.33"
33
eu.maveniverse.maven.mima.runtime:standalone-static: "2.4.33"
4+
org.apache.maven.indexer:search-backend-smo: "7.1.6"
45
info.picocli:picocli: "4.7.7"
56
org.yaml:snakeyaml: "2.4"
67
org.jline:jline-console-ui: "3.30.5"

pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
<maven.compiler.target>11</maven.compiler.target>
3434
<mainClass>org.codejive.jpm.Main</mainClass>
3535
<version.mima>2.4.34</version.mima>
36+
<version.search-backend>7.1.6</version.search-backend>
3637
<version.picocli>4.7.7</version.picocli>
3738
<version.snakeyaml>2.5</version.snakeyaml>
3839
<version.jline>3.30.5</version.jline>
@@ -55,6 +56,11 @@
5556
<artifactId>standalone-static</artifactId>
5657
<version>${version.mima}</version>
5758
</dependency>
59+
<dependency>
60+
<groupId>org.apache.maven.indexer</groupId>
61+
<artifactId>search-backend-smo</artifactId>
62+
<version>${version.search-backend}</version>
63+
</dependency>
5864
<dependency>
5965
<groupId>info.picocli</groupId>
6066
<artifactId>picocli</artifactId>

src/it/java/org/codejive/jpm/search/SearchIT.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ public class SearchIT {
1717
void testSearchSingleTerm(Search.Backends backend) throws IOException {
1818
Search s = Search.getBackend(backend);
1919
Search.SearchResult res = s.findArtifacts("httpclient", 10);
20-
assertThat(res.count).isGreaterThan(0);
20+
assertThat(res.count).isGreaterThan(1);
21+
assertThat(res.artifacts).isNotEmpty();
22+
res = s.findNextArtifacts(res);
23+
assertThat(res.count).isGreaterThan(1);
2124
assertThat(res.artifacts).isNotEmpty();
2225
}
2326

@@ -26,7 +29,10 @@ void testSearchSingleTerm(Search.Backends backend) throws IOException {
2629
void testSearchDoubleTerm(Search.Backends backend) throws IOException {
2730
Search s = Search.getBackend(backend);
2831
Search.SearchResult res = s.findArtifacts("apache:httpclient", 10);
29-
assertThat(res.count).isGreaterThan(0);
32+
assertThat(res.count).isGreaterThan(1);
33+
assertThat(res.artifacts).isNotEmpty();
34+
res = s.findNextArtifacts(res);
35+
assertThat(res.count).isGreaterThan(1);
3036
assertThat(res.artifacts).isNotEmpty();
3137
}
3238

@@ -35,7 +41,12 @@ void testSearchDoubleTerm(Search.Backends backend) throws IOException {
3541
void testSearchTripleTerm(Search.Backends backend) throws IOException {
3642
Search s = Search.getBackend(backend);
3743
Search.SearchResult res = s.findArtifacts("org.apache.httpcomponents:httpclient:", 10);
38-
assertThat(res.count).isGreaterThan(0);
44+
assertThat(res.count).isGreaterThan(1);
45+
assertThat(res.artifacts).isNotEmpty();
46+
assertThat(res.artifacts).allMatch(a -> "org.apache.httpcomponents".equals(a.getGroupId()));
47+
assertThat(res.artifacts).allMatch(a -> "httpclient".equals(a.getArtifactId()));
48+
res = s.findNextArtifacts(res);
49+
assertThat(res.count).isGreaterThan(1);
3950
assertThat(res.artifacts).isNotEmpty();
4051
assertThat(res.artifacts).allMatch(a -> "org.apache.httpcomponents".equals(a.getGroupId()));
4152
assertThat(res.artifacts).allMatch(a -> "httpclient".equals(a.getArtifactId()));

src/main/java/org/codejive/jpm/Jpm.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,22 @@ public SyncResult copy(String[] artifactNames, Map<String, String> repos, boolea
121121
* @throws IOException If an error occurred during the search.
122122
*/
123123
public String[] search(String artifactPattern, int count) throws IOException {
124+
return search(artifactPattern, count, null);
125+
}
126+
127+
/**
128+
* Searches for artifacts matching the given pattern.
129+
*
130+
* @param artifactPattern The pattern to search for.
131+
* @param count The maximum number of results to return.
132+
* @return An array of artifact names matching the given pattern.
133+
* @throws IOException If an error occurred during the search.
134+
*/
135+
public String[] search(String artifactPattern, int count, Search.Backends backend)
136+
throws IOException {
124137
List<Artifact> artifacts = new ArrayList<>();
125138
int max = count <= 0 || count > 200 ? 200 : count;
126-
Search s = Search.getBackend(null);
139+
Search s = Search.getBackend(backend);
127140
Search.SearchResult result = s.findArtifacts(artifactPattern, max);
128141
while (result != null) {
129142
artifacts.addAll(result.artifacts);

src/main/java/org/codejive/jpm/Main.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
// spotless:off Dependencies for JBang
22
//DEPS eu.maveniverse.maven.mima:context:2.4.34 eu.maveniverse.maven.mima.runtime:standalone-static:2.4.34
3+
//DEPS org.apache.maven.indexer:search-backend-smo:7.1.6
34
//DEPS info.picocli:picocli:4.7.7
45
//DEPS org.yaml:snakeyaml:2.4
56
//DEPS org.jline:jline-console-ui:3.30.5 org.jline:jline-terminal-jni:3.30.5
67
//DEPS org.slf4j:slf4j-api:2.0.17 org.slf4j:slf4j-simple:2.0.17
7-
//SOURCES Jpm.java config/AppInfo.java search/Search.java search/SearchSmoRestImpl.java util/CommandsParser.java
8-
//SOURCES util/FileUtils.java util/Resolver.java util/ScriptUtils.java util/SyncResult.java util/Version.java
8+
//SOURCES Jpm.java config/AppInfo.java search/Search.java search/SearchSmoRestImpl.java search/SearchSmoApiImpl.java
9+
//SOURCES util/CommandsParser.java util/FileUtils.java util/Resolver.java util/ScriptUtils.java util/SyncResult.java
10+
//SOURCES util/Version.java
911
// spotless:on
1012

1113
package org.codejive.jpm;
@@ -17,6 +19,7 @@
1719
import java.util.*;
1820
import java.util.concurrent.Callable;
1921
import java.util.stream.Collectors;
22+
import org.codejive.jpm.search.Search.Backends;
2023
import org.codejive.jpm.util.SyncResult;
2124
import org.codejive.jpm.util.Version;
2225
import org.jline.consoleui.elements.InputValue;
@@ -118,6 +121,12 @@ static class Search implements Callable<Integer> {
118121
description = "Maximum number of results to return")
119122
private Integer max;
120123

124+
@Option(
125+
names = {"-b", "--backend"},
126+
description =
127+
"The search backend to use. Supported values: ${COMPLETION-CANDIDATES}")
128+
private Backends backend;
129+
121130
@Parameters(
122131
paramLabel = "artifactPattern",
123132
description = "Partial or full artifact name to search for.",
@@ -194,7 +203,7 @@ String[] search(String artifactPattern) {
194203
.directory(depsMixin.directory)
195204
.noLinks(depsMixin.noLinks)
196205
.build()
197-
.search(artifactPattern, Math.min(max, 200));
206+
.search(artifactPattern, Math.min(max, 200), backend);
198207
} catch (IOException e) {
199208
throw new UncheckedIOException(e);
200209
}

src/main/java/org/codejive/jpm/search/Search.java

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,20 +33,26 @@ public interface Search {
3333
SearchResult findNextArtifacts(SearchResult prevResult) throws IOException;
3434

3535
enum Backends {
36-
SMO_REST("smo-rest");
37-
38-
public final String label;
39-
40-
Backends(String label) {
41-
this.label = label;
42-
}
36+
rest_smo,
37+
rest_csc,
38+
smo_smo,
39+
smo_csc;
4340
}
4441

4542
static Search getBackend(Backends backend) {
46-
if (backend == Backends.SMO_REST) {
47-
return new SearchSmoRestImpl();
43+
if (backend != null) {
44+
switch (backend) {
45+
case rest_smo:
46+
return SearchSolrRestImpl.createSmo();
47+
case rest_csc:
48+
return SearchSolrRestImpl.createCsc();
49+
case smo_smo:
50+
return SearchSmoApiImpl.createSmo();
51+
case smo_csc:
52+
return SearchSmoApiImpl.createCsc();
53+
}
4854
}
49-
return new SearchSmoRestImpl();
55+
return SearchSolrRestImpl.createSmo();
5056
}
5157

5258
/**
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package org.codejive.jpm.search;
2+
3+
import java.io.IOException;
4+
import java.util.List;
5+
import java.util.stream.Collectors;
6+
import org.apache.maven.search.api.MAVEN;
7+
import org.apache.maven.search.api.Record;
8+
import org.apache.maven.search.api.SearchRequest;
9+
import org.apache.maven.search.api.request.BooleanQuery;
10+
import org.apache.maven.search.api.request.FieldQuery;
11+
import org.apache.maven.search.api.request.Paging;
12+
import org.apache.maven.search.api.request.Query;
13+
import org.apache.maven.search.backend.smo.SmoSearchBackend;
14+
import org.apache.maven.search.backend.smo.SmoSearchBackendFactory;
15+
import org.apache.maven.search.backend.smo.SmoSearchResponse;
16+
import org.eclipse.aether.artifact.DefaultArtifact;
17+
18+
public class SearchSmoApiImpl implements Search {
19+
private final SmoSearchBackend backend;
20+
21+
public static Search createSmo() {
22+
return new SearchSmoApiImpl(SmoSearchBackendFactory.createSmo());
23+
}
24+
25+
public static Search createCsc() {
26+
return new SearchSmoApiImpl(SmoSearchBackendFactory.createCsc());
27+
}
28+
29+
private SearchSmoApiImpl(SmoSearchBackend backend) {
30+
this.backend = backend;
31+
}
32+
33+
@Override
34+
public SearchResult findArtifacts(String query, int count) throws IOException {
35+
return select(query, 0, count);
36+
}
37+
38+
@Override
39+
public SearchResult findNextArtifacts(SearchResult prevResult) throws IOException {
40+
return select(prevResult.query, prevResult.start + 1, prevResult.count);
41+
}
42+
43+
private SearchResult select(String query, int start, int count) throws IOException {
44+
String[] parts = query.split(":", -1);
45+
Query q;
46+
if (parts.length >= 3) {
47+
// Exact group/artifact match for retrieving versions
48+
q =
49+
BooleanQuery.and(
50+
FieldQuery.fieldQuery(MAVEN.GROUP_ID, parts[0]),
51+
FieldQuery.fieldQuery(MAVEN.ARTIFACT_ID, parts[1]));
52+
} else if (parts.length == 2) {
53+
// Partial group/artifact match, we will filter the results
54+
// to remove those that match an inverted artifact/group
55+
q = Query.query(String.format("%s %s", parts[0], parts[1]));
56+
} else {
57+
// Simple partial match
58+
q = Query.query(query);
59+
}
60+
SearchRequest req = new SearchRequest(new Paging(count, start), q);
61+
SmoSearchResponse res = backend.search(req);
62+
List<DefaultArtifact> artifacts =
63+
res.getPage().stream()
64+
.filter(r -> acceptRecord(r, parts))
65+
.map(SearchSmoApiImpl::toArtifact)
66+
.collect(Collectors.toList());
67+
return new SearchResult(
68+
artifacts,
69+
query,
70+
req.getPaging().getPageOffset(),
71+
res.getCurrentHits(),
72+
res.getTotalHits());
73+
}
74+
75+
private static boolean acceptRecord(Record r, String[] parts) {
76+
String grp = r.getValue(MAVEN.GROUP_ID);
77+
String art = r.getValue(MAVEN.ARTIFACT_ID);
78+
String pkg = r.getValue(MAVEN.PACKAGING);
79+
return pkg != null
80+
&& grp != null
81+
&& art != null
82+
&& (pkg.equals("jar") || pkg.equals("bundle"))
83+
&& (parts.length != 2 || (grp.contains(parts[0]) && art.contains(parts[1])));
84+
}
85+
86+
private static DefaultArtifact toArtifact(Record r) {
87+
String grp = r.getValue(MAVEN.GROUP_ID);
88+
String art = r.getValue(MAVEN.ARTIFACT_ID);
89+
String ver = r.getValue(MAVEN.VERSION);
90+
return new DefaultArtifact(grp, art, "", ver);
91+
}
92+
}

0 commit comments

Comments
 (0)