merge with develop

This commit is contained in:
Sebastian Sdorra
2020-06-11 08:21:06 +02:00
18 changed files with 5514 additions and 616 deletions

View File

@@ -21,12 +21,13 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package sonia.scm.api.v2.resources;
import com.github.sdorra.spotter.ContentType;
import com.github.sdorra.spotter.ContentTypes;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
@@ -44,12 +45,14 @@ import javax.ws.rs.GET;
import javax.ws.rs.HEAD;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.StreamingOutput;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
public class ContentResource {
@@ -68,11 +71,12 @@ public class ContentResource {
* Returns the content of a file for the given revision in the repository. The content type depends on the file
* content and can be discovered calling <code>HEAD</code> on the same URL. If a programming languge could be
* recognized, this will be given in the header <code>Language</code>.
*
* @param namespace the namespace of the repository
* @param namespace the namespace of the repository
* @param name the name of the repository
* @param revision the revision
* @param path The path of the file
* @param start
* @param end
*/
@GET
@Path("{revision}/{path: .*}")
@@ -94,8 +98,25 @@ public class ContentResource {
mediaType = VndMediaType.ERROR_TYPE,
schema = @Schema(implementation = ErrorDto.class)
))
public Response get(@PathParam("namespace") String namespace, @PathParam("name") String name, @PathParam("revision") String revision, @PathParam("path") String path) {
StreamingOutput stream = createStreamingOutput(namespace, name, revision, path);
@Parameter(
name = "start",
description = "If set, the content will be returned from this line on. The first line is line number 0. " +
"If omitted, the output will start with the first line."
)
@Parameter(
name = "end",
description = "If set, the content will be returned excluding the given line number and following." +
"The first line ist line number 0. " +
"If set to -1, no lines will be excluded (this equivalent to omitting this parameter"
)
public Response get(
@PathParam("namespace") String namespace,
@PathParam("name") String name,
@PathParam("revision") String revision,
@PathParam("path") String path,
@QueryParam("start") Integer start,
@QueryParam("end") Integer end) {
StreamingOutput stream = createStreamingOutput(namespace, name, revision, path, start, end);
try (RepositoryService repositoryService = serviceFactory.create(new NamespaceAndName(namespace, name))) {
Response.ResponseBuilder responseBuilder = Response.ok(stream);
return createContentHeader(namespace, name, revision, path, repositoryService, responseBuilder);
@@ -105,11 +126,23 @@ public class ContentResource {
}
}
private StreamingOutput createStreamingOutput(@PathParam("namespace") String namespace, @PathParam("name") String name, @PathParam("revision") String revision, @PathParam("path") String path) {
private StreamingOutput createStreamingOutput(String namespace, String name, String revision, String path, Integer start, Integer end) {
Integer effectiveEnd;
if (end != null && end < 0) {
effectiveEnd = null;
} else {
effectiveEnd = end;
}
return os -> {
OutputStream sourceOut;
if (start != null || effectiveEnd != null) {
sourceOut = new LineFilteredOutputStream(os, start, effectiveEnd);
} else {
sourceOut = os;
}
try (RepositoryService repositoryService = serviceFactory.create(new NamespaceAndName(namespace, name))) {
repositoryService.getCatCommand().setRevision(revision).retriveContent(os, path);
os.close();
repositoryService.getCatCommand().setRevision(revision).retriveContent(sourceOut, path);
sourceOut.close();
} catch (NotFoundException e) {
LOG.debug(e.getMessage());
throw new WebApplicationException(Status.NOT_FOUND);

View File

@@ -21,7 +21,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package sonia.scm.api.v2.resources;
import com.fasterxml.jackson.annotation.JsonInclude;
@@ -43,7 +43,11 @@ public class DiffResultDto extends HalRepresentation {
@Data
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
public static class FileDto {
public static class FileDto extends HalRepresentation {
public FileDto(Links links) {
super(links);
}
private String oldPath;
private String newPath;

View File

@@ -27,6 +27,7 @@ package sonia.scm.api.v2.resources;
import com.github.sdorra.spotter.ContentTypes;
import com.github.sdorra.spotter.Language;
import com.google.inject.Inject;
import de.otto.edison.hal.Links;
import sonia.scm.repository.Repository;
import sonia.scm.repository.api.DiffFile;
import sonia.scm.repository.api.DiffLine;
@@ -38,6 +39,7 @@ import java.util.List;
import java.util.Optional;
import java.util.OptionalInt;
import static de.otto.edison.hal.Link.linkBuilder;
import static de.otto.edison.hal.Links.linkingTo;
/**
@@ -54,26 +56,30 @@ class DiffResultToDiffResultDtoMapper {
public DiffResultDto mapForIncoming(Repository repository, DiffResult result, String source, String target) {
DiffResultDto dto = new DiffResultDto(linkingTo().self(resourceLinks.incoming().diffParsed(repository.getNamespace(), repository.getName(), source, target)).build());
setFiles(result, dto);
setFiles(result, dto, repository, source);
return dto;
}
public DiffResultDto mapForRevision(Repository repository, DiffResult result, String revision) {
DiffResultDto dto = new DiffResultDto(linkingTo().self(resourceLinks.diff().parsed(repository.getNamespace(), repository.getName(), revision)).build());
setFiles(result, dto);
setFiles(result, dto, repository, revision);
return dto;
}
private void setFiles(DiffResult result, DiffResultDto dto) {
private void setFiles(DiffResult result, DiffResultDto dto, Repository repository, String revision) {
List<DiffResultDto.FileDto> files = new ArrayList<>();
for (DiffFile file : result) {
files.add(mapFile(file));
files.add(mapFile(file, repository, revision));
}
dto.setFiles(files);
}
private DiffResultDto.FileDto mapFile(DiffFile file) {
DiffResultDto.FileDto dto = new DiffResultDto.FileDto();
private DiffResultDto.FileDto mapFile(DiffFile file, Repository repository, String revision) {
Links.Builder links = linkingTo();
if (file.iterator().hasNext()) {
links.single(linkBuilder("lines", resourceLinks.source().content(repository.getNamespace(), repository.getName(), revision, file.getNewPath()) + "?start={start}&end={end}").build());
}
DiffResultDto.FileDto dto = new DiffResultDto.FileDto(links.build());
// ???
dto.setOldEndingNewLine(true);
dto.setNewEndingNewLine(true);

View File

@@ -0,0 +1,94 @@
/*
* 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 java.io.IOException;
import java.io.OutputStream;
class LineFilteredOutputStream extends OutputStream {
private final OutputStream target;
private final int start;
private final Integer end;
private Character lastLineBreakCharacter;
private int currentLine = 0;
LineFilteredOutputStream(OutputStream target, Integer start, Integer end) {
this.target = target;
this.start = start == null ? 0 : start;
this.end = end == null ? Integer.MAX_VALUE : end;
}
@Override
public void write(int b) throws IOException {
switch (b) {
case '\n':
case '\r':
if (lastLineBreakCharacter == null) {
keepLineBreakInMind((char) b);
} else if (lastLineBreakCharacter == b) {
if (currentLine > start && currentLine <= end) {
target.write('\n');
}
++currentLine;
} else {
if (currentLine > start && currentLine <= end) {
target.write('\n');
}
lastLineBreakCharacter = null;
}
break;
default:
if (lastLineBreakCharacter != null && currentLine > start && currentLine <= end) {
target.write('\n');
}
lastLineBreakCharacter = null;
if (currentLine >= start && currentLine < end) {
target.write(b);
}
}
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
if (currentLine > end) {
return;
}
super.write(b, off, len);
}
public void keepLineBreakInMind(char b) {
lastLineBreakCharacter = b;
++currentLine;
}
@Override
public void close() throws IOException {
if (lastLineBreakCharacter != null && currentLine >= start && currentLine < end) {
target.write('\n');
}
target.close();
}
}