mirror of
https://github.com/scm-manager/scm-manager.git
synced 2026-02-07 07:09:15 +01:00
Filepath search (#1568)
Add search for files to the sources view. The search is only for finding file paths. It does not search any file metadata nor the content. Results get a rating, where file names are rated higher than file paths. The results are sorted by the score and the first 50 results are displayed. Co-authored-by: Eduard Heimbuch <eduard.heimbuch@cloudogu.com>
This commit is contained in:
@@ -40,6 +40,7 @@ public class RepositoryBasedResourceProvider {
|
||||
private final Provider<IncomingRootResource> incomingRootResource;
|
||||
private final Provider<AnnotateResource> annotateResource;
|
||||
private final Provider<RepositoryExportResource> repositoryExportResource;
|
||||
private final Provider<RepositoryPathsResource> repositoryPathResource;
|
||||
|
||||
@Inject
|
||||
public RepositoryBasedResourceProvider(
|
||||
@@ -54,7 +55,8 @@ public class RepositoryBasedResourceProvider {
|
||||
Provider<FileHistoryRootResource> fileHistoryRootResource,
|
||||
Provider<IncomingRootResource> incomingRootResource,
|
||||
Provider<AnnotateResource> annotateResource,
|
||||
Provider<RepositoryExportResource> repositoryExportResource) {
|
||||
Provider<RepositoryExportResource> repositoryExportResource,
|
||||
Provider<RepositoryPathsResource> repositoryPathResource) {
|
||||
this.tagRootResource = tagRootResource;
|
||||
this.branchRootResource = branchRootResource;
|
||||
this.changesetRootResource = changesetRootResource;
|
||||
@@ -67,6 +69,7 @@ public class RepositoryBasedResourceProvider {
|
||||
this.incomingRootResource = incomingRootResource;
|
||||
this.annotateResource = annotateResource;
|
||||
this.repositoryExportResource = repositoryExportResource;
|
||||
this.repositoryPathResource = repositoryPathResource;
|
||||
}
|
||||
|
||||
public TagRootResource getTagRootResource() {
|
||||
@@ -116,4 +119,8 @@ public class RepositoryBasedResourceProvider {
|
||||
public RepositoryExportResource getRepositoryExportResource() {
|
||||
return repositoryExportResource.get();
|
||||
}
|
||||
|
||||
public RepositoryPathsResource getRepositoryPathResource() {
|
||||
return repositoryPathResource.get();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import de.otto.edison.hal.HalRepresentation;
|
||||
import de.otto.edison.hal.Links;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@SuppressWarnings("java:S2160") // we don't need equals
|
||||
public class RepositoryPathsDto extends HalRepresentation {
|
||||
|
||||
private String revision;
|
||||
private Collection<String> paths;
|
||||
|
||||
public RepositoryPathsDto(Links links) {
|
||||
super(links);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import de.otto.edison.hal.Links;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import sonia.scm.repository.NamespaceAndName;
|
||||
import sonia.scm.repository.RepositoryPathCollector;
|
||||
import sonia.scm.repository.RepositoryPaths;
|
||||
import sonia.scm.web.VndMediaType;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import java.io.IOException;
|
||||
|
||||
public class RepositoryPathsResource {
|
||||
|
||||
private final RepositoryPathCollector collector;
|
||||
|
||||
@Inject
|
||||
public RepositoryPathsResource(RepositoryPathCollector collector) {
|
||||
this.collector = collector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all file paths for the given revision in the repository
|
||||
*
|
||||
* @param namespace the namespace of the repository
|
||||
* @param name the name of the repository
|
||||
* @param revision the revision
|
||||
*/
|
||||
@GET
|
||||
@Path("{revision}")
|
||||
@Produces(VndMediaType.REPOSITORY_PATHS)
|
||||
@Operation(summary = "File paths by revision", description = "Returns all file paths for the given revision in the repository.", tags = "Repository")
|
||||
@ApiResponse(responseCode = "200", description = "success")
|
||||
@ApiResponse(responseCode = "401", description = "not authenticated / invalid credentials")
|
||||
@ApiResponse(responseCode = "403", description = "not authorized, the current user has no privileges to read the repository")
|
||||
@ApiResponse(
|
||||
responseCode = "404",
|
||||
description = "not found, no repository with the specified name available in the namespace",
|
||||
content = @Content(
|
||||
mediaType = VndMediaType.ERROR_TYPE,
|
||||
schema = @Schema(implementation = ErrorDto.class)
|
||||
))
|
||||
@ApiResponse(
|
||||
responseCode = "500",
|
||||
description = "internal server error",
|
||||
content = @Content(
|
||||
mediaType = VndMediaType.ERROR_TYPE,
|
||||
schema = @Schema(implementation = ErrorDto.class)
|
||||
))
|
||||
public RepositoryPathsDto collect(
|
||||
@Context UriInfo uriInfo,
|
||||
@PathParam("namespace") String namespace,
|
||||
@PathParam("name") String name,
|
||||
@PathParam("revision") String revision) throws IOException
|
||||
{
|
||||
NamespaceAndName namespaceAndName = new NamespaceAndName(namespace, name);
|
||||
RepositoryPaths paths = collector.collect(namespaceAndName, revision);
|
||||
return map(uriInfo, paths);
|
||||
}
|
||||
|
||||
private RepositoryPathsDto map(UriInfo uriInfo, RepositoryPaths paths) {
|
||||
RepositoryPathsDto dto = new RepositoryPathsDto(createLinks(uriInfo));
|
||||
dto.setRevision(paths.getRevision());
|
||||
dto.setPaths(paths.getPaths());
|
||||
return dto;
|
||||
}
|
||||
|
||||
private Links createLinks(UriInfo uriInfo) {
|
||||
return Links.linkingTo().self(uriInfo.getAbsolutePath().toASCIIString()).build();
|
||||
}
|
||||
}
|
||||
@@ -337,6 +337,11 @@ public class RepositoryResource {
|
||||
return resourceProvider.getRepositoryExportResource();
|
||||
}
|
||||
|
||||
@Path("paths/")
|
||||
public RepositoryPathsResource paths() {
|
||||
return resourceProvider.getRepositoryPathResource();
|
||||
}
|
||||
|
||||
private Supplier<Repository> loadBy(String namespace, String name) {
|
||||
NamespaceAndName namespaceAndName = new NamespaceAndName(namespace, name);
|
||||
return () -> Optional.ofNullable(manager.get(namespaceAndName)).orElseThrow(() -> notFound(entity(namespaceAndName)));
|
||||
|
||||
@@ -137,6 +137,7 @@ public abstract class RepositoryToRepositoryDtoMapper extends BaseMapper<Reposit
|
||||
}
|
||||
linksBuilder.single(link("changesets", resourceLinks.changeset().all(repository.getNamespace(), repository.getName())));
|
||||
linksBuilder.single(link("sources", resourceLinks.source().selfWithoutRevision(repository.getNamespace(), repository.getName())));
|
||||
linksBuilder.single(link("paths", resourceLinks.repository().paths(repository.getNamespace(), repository.getName())));
|
||||
|
||||
Embedded.Builder embeddedBuilder = embeddedBuilder();
|
||||
applyEnrichers(new EdisonHalAppender(linksBuilder, embeddedBuilder), repository);
|
||||
|
||||
@@ -342,11 +342,13 @@ class ResourceLinks {
|
||||
private final LinkBuilder repositoryLinkBuilder;
|
||||
private final LinkBuilder repositoryImportLinkBuilder;
|
||||
private final LinkBuilder repositoryExportLinkBuilder;
|
||||
private final LinkBuilder repositoryPathsLinkBuilder;
|
||||
|
||||
RepositoryLinks(ScmPathInfo pathInfo) {
|
||||
repositoryLinkBuilder = new LinkBuilder(pathInfo, RepositoryRootResource.class, RepositoryResource.class);
|
||||
repositoryImportLinkBuilder = new LinkBuilder(pathInfo, RepositoryRootResource.class, RepositoryImportResource.class);
|
||||
repositoryExportLinkBuilder = new LinkBuilder(pathInfo, RepositoryRootResource.class, RepositoryResource.class, RepositoryExportResource.class);
|
||||
repositoryPathsLinkBuilder = new LinkBuilder(pathInfo, RepositoryRootResource.class, RepositoryResource.class, RepositoryPathsResource.class);
|
||||
}
|
||||
|
||||
String self(String namespace, String name) {
|
||||
@@ -404,6 +406,10 @@ class ResourceLinks {
|
||||
String exportInfo(String namespace, String name) {
|
||||
return repositoryExportLinkBuilder.method("getRepositoryResource").parameters(namespace, name).method("export").parameters().method("getExportInformation").parameters().href();
|
||||
}
|
||||
|
||||
String paths(String namespace, String name) {
|
||||
return repositoryPathsLinkBuilder.method("getRepositoryResource").parameters(namespace, name).method("paths").parameters().method("collect").parameters("_REVISION_").href().replace("_REVISION_", "{revision}");
|
||||
}
|
||||
}
|
||||
|
||||
RepositoryCollectionLinks repositoryCollection() {
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.repository;
|
||||
|
||||
import sonia.scm.plugin.Extension;
|
||||
import sonia.scm.repository.api.RepositoryService;
|
||||
import sonia.scm.repository.api.RepositoryServiceFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
|
||||
@Extension
|
||||
public class RepositoryPathCollector {
|
||||
|
||||
private final RepositoryServiceFactory serviceFactory;
|
||||
|
||||
@Inject
|
||||
public RepositoryPathCollector(RepositoryServiceFactory serviceFactory) {
|
||||
this.serviceFactory = serviceFactory;
|
||||
}
|
||||
|
||||
public RepositoryPaths collect(NamespaceAndName repository, String revision) throws IOException {
|
||||
BrowserResult result = browse(repository, revision);
|
||||
Collection<String> paths = new HashSet<>();
|
||||
append(paths, result.getFile());
|
||||
return new RepositoryPaths(result.getRevision(), paths);
|
||||
}
|
||||
|
||||
private BrowserResult browse(NamespaceAndName repository, String revision) throws IOException {
|
||||
try (RepositoryService repositoryService = serviceFactory.create(repository)) {
|
||||
return repositoryService.getBrowseCommand()
|
||||
.setDisableSubRepositoryDetection(true)
|
||||
.setDisableLastCommit(true)
|
||||
.setDisablePreProcessors(true)
|
||||
.setLimit(Integer.MAX_VALUE)
|
||||
.setRecursive(true)
|
||||
.setRevision(revision)
|
||||
.getBrowserResult();
|
||||
}
|
||||
}
|
||||
|
||||
private void append(Collection<String> paths, FileObject file) {
|
||||
if (file.isDirectory()) {
|
||||
for (FileObject child : file.getChildren()) {
|
||||
append(paths, child);
|
||||
}
|
||||
} else {
|
||||
paths.add(file.getPath());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.repository;
|
||||
|
||||
import lombok.Value;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@Value
|
||||
public class RepositoryPaths {
|
||||
String revision;
|
||||
Collection<String> paths;
|
||||
}
|
||||
Reference in New Issue
Block a user