Merge with 2.0.0-m3

This commit is contained in:
Florian Scholdei
2019-10-10 10:59:04 +02:00
94 changed files with 2176 additions and 481 deletions

View File

@@ -33,19 +33,15 @@ package sonia.scm.repository.spi;
import com.aragost.javahg.Changeset;
import com.aragost.javahg.commands.CommitCommand;
import com.aragost.javahg.commands.PullCommand;
import com.aragost.javahg.commands.UpdateCommand;
import org.apache.shiro.SecurityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.repository.Branch;
import sonia.scm.repository.InternalRepositoryException;
import sonia.scm.repository.Repository;
import sonia.scm.repository.api.BranchRequest;
import sonia.scm.repository.util.WorkingCopy;
import sonia.scm.user.User;
import java.io.IOException;
/**
* Mercurial implementation of the {@link BranchCommand}.
* Note that this creates an empty commit to "persist" the new branch.
@@ -63,11 +59,9 @@ public class HgBranchCommand extends AbstractCommand implements BranchCommand {
@Override
public Branch branch(BranchRequest request) {
try (WorkingCopy<com.aragost.javahg.Repository> workingCopy = workdirFactory.createWorkingCopy(getContext())) {
try (WorkingCopy<com.aragost.javahg.Repository> workingCopy = workdirFactory.createWorkingCopy(getContext(), request.getParentBranch())) {
com.aragost.javahg.Repository repository = workingCopy.getWorkingRepository();
checkoutParentBranchIfSpecified(request, repository);
Changeset emptyChangeset = createNewBranchWithEmptyCommit(request, repository);
LOG.debug("Created new branch '{}' in repository {} with changeset {}",
@@ -79,16 +73,6 @@ public class HgBranchCommand extends AbstractCommand implements BranchCommand {
}
}
private void checkoutParentBranchIfSpecified(BranchRequest request, com.aragost.javahg.Repository repository) {
if (request.getParentBranch() != null) {
try {
UpdateCommand.on(repository).rev(request.getParentBranch()).execute();
} catch (IOException e) {
throw new InternalRepositoryException(getRepository(), "Could not check out parent branch " + request.getParentBranch(), e);
}
}
}
private Changeset createNewBranchWithEmptyCommit(BranchRequest request, com.aragost.javahg.Repository repository) {
com.aragost.javahg.commands.BranchCommand.on(repository).set(request.getNewBranch());
User currentUser = SecurityUtils.getSubject().getPrincipals().oneByType(User.class);

View File

@@ -39,13 +39,12 @@ import com.google.common.base.Strings;
import com.google.common.io.ByteStreams;
import com.google.common.io.Closeables;
import sonia.scm.repository.Repository;
import sonia.scm.repository.api.DiffCommandBuilder;
import sonia.scm.repository.api.DiffFormat;
import sonia.scm.repository.spi.javahg.HgDiffInternalCommand;
import sonia.scm.web.HgUtil;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
//~--- JDK imports ------------------------------------------------------------
@@ -71,41 +70,36 @@ public class HgDiffCommand extends AbstractCommand implements DiffCommand
//~--- get methods ----------------------------------------------------------
@Override
public void getDiffResult(DiffCommandRequest request, OutputStream output)
throws IOException
public DiffCommandBuilder.OutputStreamConsumer getDiffResult(DiffCommandRequest request)
{
com.aragost.javahg.Repository hgRepo = open();
return output -> {
com.aragost.javahg.Repository hgRepo = open();
HgDiffInternalCommand cmd = HgDiffInternalCommand.on(hgRepo);
DiffFormat format = request.getFormat();
HgDiffInternalCommand cmd = HgDiffInternalCommand.on(hgRepo);
DiffFormat format = request.getFormat();
if (format == DiffFormat.GIT)
{
cmd.git();
}
cmd.change(HgUtil.getRevision(request.getRevision()));
InputStream inputStream = null;
try
{
if (!Strings.isNullOrEmpty(request.getPath()))
if (format == DiffFormat.GIT)
{
inputStream = cmd.stream(hgRepo.file(request.getPath()));
}
else
{
inputStream = cmd.stream();
cmd.git();
}
ByteStreams.copy(inputStream, output);
cmd.change(HgUtil.getRevision(request.getRevision()));
}
finally
{
Closeables.close(inputStream, true);
}
InputStream inputStream = null;
try {
if (!Strings.isNullOrEmpty(request.getPath())) {
inputStream = cmd.stream(hgRepo.file(request.getPath()));
} else {
inputStream = cmd.stream();
}
ByteStreams.copy(inputStream, output);
} finally {
Closeables.close(inputStream, true);
}
};
}
}

View File

@@ -0,0 +1,103 @@
package sonia.scm.repository.spi;
import com.aragost.javahg.Changeset;
import com.aragost.javahg.Repository;
import com.aragost.javahg.commands.CommitCommand;
import com.aragost.javahg.commands.ExecutionException;
import com.aragost.javahg.commands.PullCommand;
import com.aragost.javahg.commands.RemoveCommand;
import com.aragost.javahg.commands.StatusCommand;
import sonia.scm.NoChangesMadeException;
import sonia.scm.repository.InternalRepositoryException;
import sonia.scm.repository.util.WorkingCopy;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.List;
public class HgModifyCommand implements ModifyCommand {
private HgCommandContext context;
private final HgWorkdirFactory workdirFactory;
public HgModifyCommand(HgCommandContext context, HgWorkdirFactory workdirFactory) {
this.context = context;
this.workdirFactory = workdirFactory;
}
@Override
public String execute(ModifyCommandRequest request) {
try (WorkingCopy<com.aragost.javahg.Repository> workingCopy = workdirFactory.createWorkingCopy(context, request.getBranch())) {
Repository workingRepository = workingCopy.getWorkingRepository();
request.getRequests().forEach(
partialRequest -> {
try {
partialRequest.execute(new ModifyWorkerHelper() {
@Override
public void addFileToScm(String name, Path file) {
try {
addFileToHg(file.toFile());
} catch (ExecutionException e) {
throwInternalRepositoryException("could not add new file to index", e);
}
}
@Override
public void doScmDelete(String toBeDeleted) {
RemoveCommand.on(workingRepository).execute(toBeDeleted);
}
@Override
public sonia.scm.repository.Repository getRepository() {
return context.getScmRepository();
}
@Override
public String getBranch() {
return request.getBranch();
}
public File getWorkDir() {
return workingRepository.getDirectory();
}
private void addFileToHg(File file) {
workingRepository.workingCopy().add(file.getAbsolutePath());
}
});
} catch (IOException e) {
throwInternalRepositoryException("could not execute command on repository", e);
}
}
);
if (StatusCommand.on(workingRepository).lines().isEmpty()) {
throw new NoChangesMadeException(context.getScmRepository());
}
CommitCommand.on(workingRepository).user(String.format("%s <%s>", request.getAuthor().getName(), request.getAuthor().getMail())).message(request.getCommitMessage()).execute();
List<Changeset> execute = pullModifyChangesToCentralRepository(request, workingCopy);
return execute.get(0).getNode();
} catch (ExecutionException e) {
throwInternalRepositoryException("could not execute command on repository", e);
return null;
}
}
private List<Changeset> pullModifyChangesToCentralRepository(ModifyCommandRequest request, WorkingCopy<com.aragost.javahg.Repository> workingCopy) {
try {
com.aragost.javahg.commands.PullCommand pullCommand = PullCommand.on(workingCopy.getCentralRepository());
workdirFactory.configure(pullCommand);
return pullCommand.execute(workingCopy.getDirectory().getAbsolutePath());
} catch (Exception e) {
throw new IntegrateChangesFromWorkdirException(context.getScmRepository(),
String.format("Could not pull modify changes from working copy to central repository for branch %s", request.getBranch()),
e);
}
}
private String throwInternalRepositoryException(String message, Exception e) {
throw new InternalRepositoryException(context.getScmRepository(), message, e);
}
}

View File

@@ -66,7 +66,8 @@ public class HgRepositoryServiceProvider extends RepositoryServiceProvider
Command.INCOMING,
Command.OUTGOING,
Command.PUSH,
Command.PULL
Command.PULL,
Command.MODIFY
);
//J+
@@ -77,7 +78,7 @@ public class HgRepositoryServiceProvider extends RepositoryServiceProvider
//~--- constructors ---------------------------------------------------------
HgRepositoryServiceProvider(HgRepositoryHandler handler,
HgHookManager hookManager, Repository repository)
HgHookManager hookManager, Repository repository)
{
this.repository = repository;
this.handler = handler;
@@ -238,6 +239,11 @@ public class HgRepositoryServiceProvider extends RepositoryServiceProvider
return new HgPushCommand(handler, context, repository);
}
@Override
public ModifyCommand getModifyCommand() {
return new HgModifyCommand(context, handler.getWorkdirFactory());
}
/**
* Method description
*

View File

@@ -47,12 +47,12 @@ import sonia.scm.repository.Repository;
public class HgRepositoryServiceResolver implements RepositoryServiceResolver
{
private HgRepositoryHandler handler;
private HgHookManager hookManager;
private final HgRepositoryHandler handler;
private final HgHookManager hookManager;
@Inject
public HgRepositoryServiceResolver(HgRepositoryHandler handler,
HgHookManager hookManager)
HgHookManager hookManager)
{
this.handler = handler;
this.hookManager = hookManager;

View File

@@ -1,8 +1,10 @@
package sonia.scm.repository.spi;
import com.aragost.javahg.BaseRepository;
import com.aragost.javahg.Repository;
import com.aragost.javahg.commands.CloneCommand;
import com.aragost.javahg.commands.PullCommand;
import com.aragost.javahg.commands.flags.CloneCommandFlags;
import sonia.scm.repository.util.SimpleWorkdirFactory;
import sonia.scm.repository.util.WorkdirProvider;
import sonia.scm.web.HgRepositoryEnvironmentBuilder;
@@ -24,12 +26,19 @@ public class SimpleHgWorkdirFactory extends SimpleWorkdirFactory<Repository, HgC
this.hgRepositoryEnvironmentBuilder = hgRepositoryEnvironmentBuilder;
}
@Override
public ParentAndClone<Repository> cloneRepository(HgCommandContext context, File target) throws IOException {
public ParentAndClone<Repository> cloneRepository(HgCommandContext context, File target, String initialBranch) throws IOException {
BiConsumer<sonia.scm.repository.Repository, Map<String, String>> repositoryMapBiConsumer =
(repository, environment) -> hgRepositoryEnvironmentBuilder.get().buildFor(repository, null, environment);
Repository centralRepository = context.openWithSpecialEnvironment(repositoryMapBiConsumer);
CloneCommand.on(centralRepository).execute(target.getAbsolutePath());
return new ParentAndClone<>(centralRepository, Repository.open(target));
CloneCommand cloneCommand = CloneCommandFlags.on(centralRepository);
if (initialBranch != null) {
cloneCommand.updaterev(initialBranch);
}
cloneCommand.execute(target.getAbsolutePath());
BaseRepository clone = Repository.open(target);
return new ParentAndClone<>(centralRepository, clone);
}
@Override

View File

@@ -1,8 +1,8 @@
#
# Copyright (c) 2010, Sebastian Sdorra
# All rights reserved.
# aLL rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# rEDistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
@@ -34,7 +34,7 @@ Prints date, size and last message of files.
"""
from collections import defaultdict
from mercurial import cmdutil,util
from mercurial import scmutil
cmdtable = {}
@@ -122,7 +122,7 @@ class File_Object:
return result
class File_Walker:
def __init__(self, sub_repositories, visitor):
self.visitor = visitor
self.sub_repositories = sub_repositories
@@ -273,7 +273,7 @@ class File_Viewer:
('t', 'transport', False, 'format the output for command server'),
])
def fileview(ui, repo, **opts):
revCtx = repo[opts["revision"]]
revCtx = scmutil.revsingle(repo, opts["revision"])
subrepos = {}
if not opts["disableSubRepositoryDetection"]:
subrepos = collect_sub_repositories(revCtx)

View File

@@ -2,7 +2,7 @@ package sonia.scm.repository.spi;
import com.aragost.javahg.commands.PullCommand;
import com.google.inject.util.Providers;
import org.assertj.core.api.Assertions;
import org.junit.Before;
import org.junit.Test;
import sonia.scm.repository.Branch;
import sonia.scm.repository.HgTestUtil;
@@ -10,30 +10,48 @@ import sonia.scm.repository.api.BranchRequest;
import sonia.scm.repository.util.WorkdirProvider;
import sonia.scm.web.HgRepositoryEnvironmentBuilder;
import java.io.IOException;
import java.util.List;
public class HgBranchCommandTest extends AbstractHgCommandTestBase {
@Test
public void shouldCreateBranch() throws IOException {
Assertions.assertThat(readBranches()).filteredOn(b -> b.getName().equals("new_branch")).isEmpty();
import static org.assertj.core.api.Assertions.assertThat;
public class HgBranchCommandTest extends AbstractHgCommandTestBase {
private SimpleHgWorkdirFactory workdirFactory;
@Before
public void initWorkdirFactory() {
HgRepositoryEnvironmentBuilder hgRepositoryEnvironmentBuilder =
new HgRepositoryEnvironmentBuilder(handler, HgTestUtil.createHookManager());
SimpleHgWorkdirFactory workdirFactory = new SimpleHgWorkdirFactory(Providers.of(hgRepositoryEnvironmentBuilder), new WorkdirProvider()) {
workdirFactory = new SimpleHgWorkdirFactory(Providers.of(hgRepositoryEnvironmentBuilder), new WorkdirProvider()) {
@Override
public void configure(PullCommand pullCommand) {
// we do not want to configure http hooks in this unit test
}
};
}
@Test
public void shouldCreateBranch() {
BranchRequest branchRequest = new BranchRequest();
branchRequest.setNewBranch("new_branch");
new HgBranchCommand(cmdContext, repository, workdirFactory).branch(branchRequest);
Branch newBranch = new HgBranchCommand(cmdContext, repository, workdirFactory).branch(branchRequest);
Assertions.assertThat(readBranches()).filteredOn(b -> b.getName().equals("new_branch")).isNotEmpty();
assertThat(readBranches()).filteredOn(b -> b.getName().equals("new_branch")).isNotEmpty();
assertThat(cmdContext.open().changeset(newBranch.getRevision()).getParent1().getBranch()).isEqualTo("default");
}
@Test
public void shouldCreateBranchOnSpecificParent() {
BranchRequest branchRequest = new BranchRequest();
branchRequest.setParentBranch("test-branch");
branchRequest.setNewBranch("new_branch");
Branch newBranch = new HgBranchCommand(cmdContext, repository, workdirFactory).branch(branchRequest);
assertThat(readBranches()).filteredOn(b -> b.getName().equals("new_branch")).isNotEmpty();
assertThat(cmdContext.open().changeset(newBranch.getRevision()).getParent1().getBranch()).isEqualTo("test-branch");
}
private List<Branch> readBranches() {

View File

@@ -0,0 +1,164 @@
package sonia.scm.repository.spi;
import com.google.inject.util.Providers;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import sonia.scm.AlreadyExistsException;
import sonia.scm.NoChangesMadeException;
import sonia.scm.NotFoundException;
import sonia.scm.repository.HgHookManager;
import sonia.scm.repository.HgTestUtil;
import sonia.scm.repository.Person;
import sonia.scm.repository.util.WorkdirProvider;
import sonia.scm.web.HgRepositoryEnvironmentBuilder;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import static org.assertj.core.api.Assertions.assertThat;
public class HgModifyCommandTest extends AbstractHgCommandTestBase {
private HgModifyCommand hgModifyCommand;
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();
@Before
public void initHgModifyCommand() {
HgHookManager hookManager = HgTestUtil.createHookManager();
HgRepositoryEnvironmentBuilder environmentBuilder = new HgRepositoryEnvironmentBuilder(handler, hookManager);
SimpleHgWorkdirFactory workdirFactory = new SimpleHgWorkdirFactory(Providers.of(environmentBuilder), new WorkdirProvider()) {
@Override
public void configure(com.aragost.javahg.commands.PullCommand pullCommand) {
// we do not want to configure http hooks in this unit test
}
};
hgModifyCommand = new HgModifyCommand(cmdContext, workdirFactory
);
}
@Test
public void shouldRemoveFiles() {
ModifyCommandRequest request = new ModifyCommandRequest();
request.addRequest(new ModifyCommandRequest.DeleteFileRequest("a.txt"));
request.setCommitMessage("this is great");
request.setAuthor(new Person("Arthur Dent", "dent@hitchhiker.com"));
String result = hgModifyCommand.execute(request);
assertThat(cmdContext.open().tip().getNode()).isEqualTo(result);
}
@Test
public void shouldCreateFilesWithoutOverwrite() throws IOException {
File testFile = temporaryFolder.newFile();
ModifyCommandRequest request = new ModifyCommandRequest();
request.addRequest(new ModifyCommandRequest.CreateFileRequest("Answer.txt", testFile, false));
request.setCommitMessage("I found the answer");
request.setAuthor(new Person("Trillian Astra", "trillian@hitchhiker.com"));
String changeSet = hgModifyCommand.execute(request);
assertThat(cmdContext.open().tip().getNode()).isEqualTo(changeSet);
assertThat(cmdContext.open().tip().getAddedFiles().size()).isEqualTo(1);
}
@Test
public void shouldOverwriteExistingFiles() throws IOException {
File testFile = temporaryFolder.newFile();
new FileOutputStream(testFile).write(42);
ModifyCommandRequest request2 = new ModifyCommandRequest();
request2.addRequest(new ModifyCommandRequest.CreateFileRequest("a.txt", testFile, true));
request2.setCommitMessage(" Now i really found the answer");
request2.setAuthor(new Person("Trillian Astra", "trillian@hitchhiker.com"));
String changeSet2 = hgModifyCommand.execute(request2);
assertThat(cmdContext.open().tip().getNode()).isEqualTo(changeSet2);
assertThat(cmdContext.open().tip().getModifiedFiles().size()).isEqualTo(1);
assertThat(cmdContext.open().tip().getModifiedFiles().get(0)).isEqualTo("a.txt");
}
@Test(expected = AlreadyExistsException.class)
public void shouldThrowFileAlreadyExistsException() throws IOException {
File testFile = temporaryFolder.newFile();
new FileOutputStream(testFile).write(21);
ModifyCommandRequest request = new ModifyCommandRequest();
request.addRequest(new ModifyCommandRequest.CreateFileRequest("Answer.txt", testFile, false));
request.setCommitMessage("I found the answer");
request.setAuthor(new Person("Trillian Astra", "trillian@hitchhiker.com"));
hgModifyCommand.execute(request);
new FileOutputStream(testFile).write(42);
ModifyCommandRequest request2 = new ModifyCommandRequest();
request2.addRequest(new ModifyCommandRequest.CreateFileRequest("Answer.txt", testFile, false));
request2.setCommitMessage(" Now i really found the answer");
request2.setAuthor(new Person("Trillian Astra", "trillian@hitchhiker.com"));
hgModifyCommand.execute(request2);
}
@Test
public void shouldModifyExistingFile() throws IOException {
File testFile = temporaryFolder.newFile("a.txt");
new FileOutputStream(testFile).write(42);
ModifyCommandRequest request2 = new ModifyCommandRequest();
request2.addRequest(new ModifyCommandRequest.ModifyFileRequest("a.txt", testFile));
request2.setCommitMessage(" Now i really found the answer");
request2.setAuthor(new Person("Trillian Astra", "trillian@hitchhiker.com"));
String changeSet2 = hgModifyCommand.execute(request2);
assertThat(cmdContext.open().tip().getNode()).isEqualTo(changeSet2);
assertThat(cmdContext.open().tip().getModifiedFiles().size()).isEqualTo(1);
assertThat(cmdContext.open().tip().getModifiedFiles().get(0)).isEqualTo(testFile.getName());
}
@Test(expected = NotFoundException.class)
public void shouldThrowNotFoundExceptionIfFileDoesNotExist() throws IOException {
File testFile = temporaryFolder.newFile("Answer.txt");
new FileOutputStream(testFile).write(42);
ModifyCommandRequest request2 = new ModifyCommandRequest();
request2.addRequest(new ModifyCommandRequest.ModifyFileRequest("Answer.txt", testFile));
request2.setCommitMessage(" Now i really found the answer");
request2.setAuthor(new Person("Trillian Astra", "trillian@hitchhiker.com"));
hgModifyCommand.execute(request2);
}
@Test(expected = NullPointerException.class)
public void shouldThrowNPEIfAuthorIsMissing() throws IOException {
File testFile = temporaryFolder.newFile();
ModifyCommandRequest request = new ModifyCommandRequest();
request.addRequest(new ModifyCommandRequest.CreateFileRequest("Answer.txt", testFile, false));
request.setCommitMessage("I found the answer");
hgModifyCommand.execute(request);
}
@Test(expected = NullPointerException.class)
public void shouldThrowNPEIfCommitMessageIsMissing() throws IOException {
File testFile = temporaryFolder.newFile();
ModifyCommandRequest request = new ModifyCommandRequest();
request.addRequest(new ModifyCommandRequest.CreateFileRequest("Answer.txt", testFile, false));
request.setAuthor(new Person("Trillian Astra", "trillian@hitchhiker.com"));
hgModifyCommand.execute(request);
}
@Test(expected = NoChangesMadeException.class)
public void shouldThrowNoChangesMadeExceptionIfEmptyLocalChangesetAfterRequest() {
hgModifyCommand.execute(new ModifyCommandRequest());
}
}