Detect missing paths in hg fileview command

If a not existing path is request in the fileview command, it will
be treated as an empty directory. But such a thing does not exist in hg.
Therefore we handle this result as what it is: a not existing path -
and we throw a not found exception.
This commit is contained in:
René Pfeuffer
2020-09-22 17:29:40 +02:00
parent fc534605f0
commit 059482f8ab
5 changed files with 43 additions and 18 deletions

View File

@@ -1,3 +1,4 @@
# Changelog
All notable changes to this project will be documented in this file.
@@ -17,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Overflow for too long branch names ([#1339](https://github.com/scm-manager/scm-manager/pull/1339))
- Set default branch in branch selector if nothing is selected ([#1338](https://github.com/scm-manager/scm-manager/pull/1338))
- Handling of branch with slashes in source view ([#1340](https://github.com/scm-manager/scm-manager/pull/1340))
- Detect not existing paths correctly in Mercurial ([#1343](https://github.com/scm-manager/scm-manager/pull/1343))
## [2.5.0] - 2020-09-10
### Added

View File

@@ -36,6 +36,9 @@ import sonia.scm.repository.spi.javahg.HgFileviewCommand;
import java.io.IOException;
import static sonia.scm.ContextEntry.ContextBuilder.entity;
import static sonia.scm.NotFoundException.notFound;
//~--- JDK imports ------------------------------------------------------------
/**
@@ -93,7 +96,8 @@ public class HgBrowseCommand extends AbstractCommand implements BrowseCommand
cmd.setLimit(request.getLimit());
cmd.setOffset(request.getOffset());
FileObject file = cmd.execute();
FileObject file = cmd.execute()
.orElseThrow(() -> notFound(entity("File", request.getPath()).in("Revision", revision).in(getRepository())));
return new BrowserResult(c == null? "tip": c.getNode(), revision, file);
}
}

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.repository.spi.javahg;
//~--- non-JDK imports --------------------------------------------------------
@@ -29,12 +29,12 @@ package sonia.scm.repository.spi.javahg;
import com.aragost.javahg.Repository;
import com.aragost.javahg.internals.AbstractCommand;
import com.aragost.javahg.internals.HgInputStream;
import sonia.scm.repository.FileObject;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
import java.util.Optional;
/**
* Mercurial command to list files of a repository.
@@ -161,7 +161,7 @@ public class HgFileviewCommand extends AbstractCommand
*
* @throws IOException
*/
public FileObject execute() throws IOException
public Optional<FileObject> execute() throws IOException
{
cmdAppend("-t");

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.repository.spi.javahg;
import com.aragost.javahg.DateTime;
@@ -35,6 +35,10 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Deque;
import java.util.LinkedList;
import java.util.Optional;
import static java.util.Optional.empty;
import static java.util.Optional.of;
class HgFileviewCommandResultReader {
@@ -48,7 +52,7 @@ class HgFileviewCommandResultReader {
this.disableLastCommit = disableLastCommit;
}
FileObject parseResult() throws IOException {
Optional<FileObject> parseResult() throws IOException {
Deque<FileObject> stack = new LinkedList<>();
FileObject last = null;
@@ -82,13 +86,17 @@ class HgFileviewCommandResultReader {
if (stack.isEmpty()) {
// if the stack is empty, the requested path is probably a file
return last;
return of(last);
} else if (stack.size() == 1 && stack.getFirst().isDirectory() && stack.getFirst().getChildren().isEmpty()) {
// There are no empty directories in hg. When we get this,
// we just get the requested path as a directory, but it does not exist.
return empty();
} else {
// if the stack is not empty, the requested path is a directory
if (stream.read() == TRUNCATED_MARK) {
stack.getLast().setTruncated(true);
}
return stack.getLast();
return of(stack.getLast());
}
}

View File

@@ -21,11 +21,10 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package sonia.scm.repository.spi.javahg;
import com.aragost.javahg.internals.HgInputStream;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import sonia.scm.repository.FileObject;
@@ -34,6 +33,7 @@ import java.io.IOException;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Iterator;
import java.util.Optional;
import java.util.OptionalLong;
import static java.nio.charset.StandardCharsets.UTF_8;
@@ -55,7 +55,7 @@ class HgFileviewCommandResultReaderTest {
.file("b.txt", 100, time2.toEpochMilli(), "file b\nwith some\nmore text")
.build();
FileObject fileObject = reader.parseResult();
FileObject fileObject = reader.parseResult().get();
assertThat(fileObject.isDirectory()).isTrue();
assertThat(fileObject.getChildren())
@@ -84,7 +84,7 @@ class HgFileviewCommandResultReaderTest {
.file("a.txt")
.truncated();
FileObject fileObject = reader.parseResult();
FileObject fileObject = reader.parseResult().get();
assertThat(fileObject.isTruncated()).isTrue();
}
@@ -96,7 +96,7 @@ class HgFileviewCommandResultReaderTest {
.file("dir/a.txt")
.build();
FileObject fileObject = reader.parseResult();
FileObject fileObject = reader.parseResult().get();
assertThat(fileObject.isDirectory()).isTrue();
assertThat(fileObject.getName()).isEqualTo("dir");
@@ -117,7 +117,7 @@ class HgFileviewCommandResultReaderTest {
.file("d.txt")
.build();
FileObject fileObject = reader.parseResult();
FileObject fileObject = reader.parseResult().get();
assertThat(fileObject.getChildren())
.extracting("name")
@@ -152,7 +152,7 @@ class HgFileviewCommandResultReaderTest {
.file("d.txt")
.build();
FileObject fileObject = reader.parseResult();
FileObject fileObject = reader.parseResult().get();
assertThat(fileObject.getChildren())
.extracting("name")
@@ -179,7 +179,7 @@ class HgFileviewCommandResultReaderTest {
.file("d.txt")
.build();
FileObject fileObject = reader.parseResult();
FileObject fileObject = reader.parseResult().get();
assertThat(fileObject.getChildren())
.extracting("name")
@@ -213,7 +213,7 @@ class HgFileviewCommandResultReaderTest {
.file("directory/b.txt")
.build();
FileObject fileObject = reader.parseResult();
FileObject fileObject = reader.parseResult().get();
assertThat(fileObject.getChildren())
.extracting("name")
@@ -248,7 +248,7 @@ class HgFileviewCommandResultReaderTest {
.file("a.txt")
.build();
FileObject fileObject = reader.parseResult();
FileObject fileObject = reader.parseResult().get();
assertThat(fileObject.getChildren())
.extracting("description")
@@ -258,6 +258,17 @@ class HgFileviewCommandResultReaderTest {
.containsOnly(OptionalLong.empty());
}
@Test
void shouldIgnoreSingleEmptyDir() throws IOException {
HgFileviewCommandResultReader reader = new MockInput()
.dir("empty")
.build();
Optional<FileObject> fileObject = reader.parseResult();
assertThat(fileObject).isEmpty();
}
private HgInputStream createInputStream(String input) {
return new HgInputStream(new ByteArrayInputStream(input.getBytes(UTF_8)), UTF_8.newDecoder());
}