mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-12 16:35:45 +01:00
merge with develop
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user