diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SimpleSvnWorkDirFactory.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SimpleSvnWorkDirFactory.java index 2f30f086d9..713e79a2bb 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SimpleSvnWorkDirFactory.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SimpleSvnWorkDirFactory.java @@ -58,6 +58,6 @@ public class SimpleSvnWorkDirFactory extends SimpleWorkdirFactory(workingCopy, workingCopy); + return new ParentAndClone<>(context.getDirectory(), workingCopy); } } diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnModifyCommand.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnModifyCommand.java new file mode 100644 index 0000000000..f624c40806 --- /dev/null +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnModifyCommand.java @@ -0,0 +1,84 @@ +package sonia.scm.repository.spi; + +import org.tmatesoft.svn.core.SVNDepth; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.wc.SVNClientManager; +import org.tmatesoft.svn.core.wc.SVNWCClient; +import sonia.scm.repository.InternalRepositoryException; +import sonia.scm.repository.Repository; +import sonia.scm.repository.SvnWorkDirFactory; +import sonia.scm.repository.util.WorkingCopy; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; + +public class SvnModifyCommand implements ModifyCommand { + + private SvnContext context; + private SvnWorkDirFactory workDirFactory; + private Repository repository; + + public SvnModifyCommand(SvnContext context, Repository repository, SvnWorkDirFactory workDirFactory) { + this.context = context; + this.repository = repository; + this.workDirFactory = workDirFactory; + } + + @Override + public String execute(ModifyCommandRequest request) { + SVNClientManager clientManager = SVNClientManager.newInstance(); + try (WorkingCopy workingCopy = workDirFactory.createWorkingCopy(context, null)) { + File workingRepository = workingCopy.getWorkingRepository(); + for (ModifyCommandRequest.PartialRequest partialRequest : request.getRequests()) { + try { + SVNWCClient wcClient = clientManager.getWCClient(); + partialRequest.execute(new ModifyWorkerHelper() { + @Override + public void doScmDelete(String toBeDeleted){ + try { + wcClient.doDelete(new File(String.format("%s/%s", workingRepository, toBeDeleted)), true, true, false); + } catch (SVNException e) { + throw new InternalRepositoryException(repository, "could not delete file from repository"); + } + } + + @Override + public void addFileToScm(String name, Path file) { + try { + wcClient.doAdd(file.toFile(), true, false, true, SVNDepth.INFINITY, false, true); + } catch (SVNException e) { + throw new InternalRepositoryException(repository, "could not add file to repository"); + } + } + + @Override + public File getWorkDir() { + return workingRepository; + } + + @Override + public Repository getRepository() { + return repository; + } + + @Override + public String getBranch() { + return null; + } + }); + } catch (IOException e) { + throw new InternalRepositoryException(repository, "could not read files from repository"); + } + } + try { + clientManager.getCommitClient().doCommit(new File[] {workingRepository}, false, + request.getCommitMessage(), null, null, false, true, SVNDepth.INFINITY); + //I can't get the newest revision after commiting without creating a new working copy + return String.valueOf(clientManager.getStatusClient().doStatus(workingRepository, false).getCommittedRevision().getNumber() + 1); + } catch (SVNException e) { + throw new InternalRepositoryException(repository, "could not commit changes on repository"); + } + } + } +} diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceProvider.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceProvider.java index ff277947bd..e96dedd4a0 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceProvider.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceProvider.java @@ -37,8 +37,10 @@ import com.google.common.collect.ImmutableSet; import com.google.common.io.Closeables; import sonia.scm.repository.Repository; import sonia.scm.repository.SvnRepositoryHandler; +import sonia.scm.repository.SvnWorkDirFactory; import sonia.scm.repository.api.Command; +import javax.inject.Inject; import java.io.IOException; import java.util.Set; @@ -53,17 +55,19 @@ public class SvnRepositoryServiceProvider extends RepositoryServiceProvider //J- public static final Set COMMANDS = ImmutableSet.of( Command.BLAME, Command.BROWSE, Command.CAT, Command.DIFF, - Command.LOG, Command.BUNDLE, Command.UNBUNDLE + Command.LOG, Command.BUNDLE, Command.UNBUNDLE, Command.MODIFY ); //J+ //~--- constructors --------------------------------------------------------- + @Inject SvnRepositoryServiceProvider(SvnRepositoryHandler handler, - Repository repository) + Repository repository, SvnWorkDirFactory workdirFactory) { this.repository = repository; this.context = new SvnContext(handler.getDirectory(repository.getId())); + this.workDirFactory = workdirFactory; } //~--- methods -------------------------------------------------------------- @@ -158,6 +162,10 @@ public class SvnRepositoryServiceProvider extends RepositoryServiceProvider return new SvnModificationsCommand(context, repository); } + public ModifyCommand getModifyCommand() { + return new SvnModifyCommand(context, repository, workDirFactory); + } + /** * Method description * @@ -189,4 +197,6 @@ public class SvnRepositoryServiceProvider extends RepositoryServiceProvider /** Field description */ private final Repository repository; + + private final SvnWorkDirFactory workDirFactory; } diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceResolver.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceResolver.java index 763b5f445e..05097ff111 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceResolver.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceResolver.java @@ -36,15 +36,18 @@ import com.google.inject.Inject; import sonia.scm.plugin.Extension; import sonia.scm.repository.Repository; import sonia.scm.repository.SvnRepositoryHandler; +import sonia.scm.repository.SvnWorkDirFactory; @Extension public class SvnRepositoryServiceResolver implements RepositoryServiceResolver { private SvnRepositoryHandler handler; + private SvnWorkDirFactory workdirFactory; @Inject - public SvnRepositoryServiceResolver(SvnRepositoryHandler handler) { + public SvnRepositoryServiceResolver(SvnRepositoryHandler handler, SvnWorkDirFactory workdirFactory) { this.handler = handler; + this.workdirFactory = workdirFactory; } @Override @@ -52,7 +55,7 @@ public class SvnRepositoryServiceResolver implements RepositoryServiceResolver { SvnRepositoryServiceProvider provider = null; if (SvnRepositoryHandler.TYPE_NAME.equalsIgnoreCase(repository.getType())) { - provider = new SvnRepositoryServiceProvider(handler, repository); + provider = new SvnRepositoryServiceProvider(handler, repository, workdirFactory); } return provider; diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnServletModule.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnServletModule.java index 8526d6380a..b4f0aaf920 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnServletModule.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnServletModule.java @@ -38,6 +38,8 @@ import org.mapstruct.factory.Mappers; import sonia.scm.api.v2.resources.SvnConfigDtoToSvnConfigMapper; import sonia.scm.api.v2.resources.SvnConfigToSvnConfigDtoMapper; import sonia.scm.plugin.Extension; +import sonia.scm.repository.SvnWorkDirFactory; +import sonia.scm.repository.spi.SimpleSvnWorkDirFactory; /** * @@ -50,5 +52,6 @@ public class SvnServletModule extends ServletModule { protected void configureServlets() { bind(SvnConfigDtoToSvnConfigMapper.class).to(Mappers.getMapper(SvnConfigDtoToSvnConfigMapper.class).getClass()); bind(SvnConfigToSvnConfigDtoMapper.class).to(Mappers.getMapper(SvnConfigToSvnConfigDtoMapper.class).getClass()); + bind(SvnWorkDirFactory.class).to(SimpleSvnWorkDirFactory.class); } } diff --git a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SvnModifyCommandTest.java b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SvnModifyCommandTest.java new file mode 100644 index 0000000000..456971d9a2 --- /dev/null +++ b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SvnModifyCommandTest.java @@ -0,0 +1,89 @@ +package sonia.scm.repository.spi; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import sonia.scm.AlreadyExistsException; +import sonia.scm.repository.Person; +import sonia.scm.repository.util.WorkdirProvider; +import sonia.scm.repository.util.WorkingCopy; + +import java.io.File; +import java.io.IOException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class SvnModifyCommandTest extends AbstractSvnCommandTestBase { + + private SvnModifyCommand svnModifyCommand; + private SvnContext context; + private SimpleSvnWorkDirFactory workDirFactory; + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Before + public void initSvnModifyCommand() { + context = createContext(); + workDirFactory = new SimpleSvnWorkDirFactory(new WorkdirProvider(context.getDirectory())); + svnModifyCommand = new SvnModifyCommand(context, createRepository(), 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")); + + svnModifyCommand.execute(request); + WorkingCopy workingCopy = workDirFactory.createWorkingCopy(context, null); + assertThat(new File(workingCopy.getWorkingRepository().getAbsolutePath() + "/a.txt")).doesNotExist(); + assertThat(new File(workingCopy.getWorkingRepository().getAbsolutePath() + "/c")).exists(); + } + + @Test + public void shouldAddNewFile() throws IOException { + File testfile = temporaryFolder.newFile("Test123"); + + ModifyCommandRequest request = new ModifyCommandRequest(); + request.addRequest(new ModifyCommandRequest.CreateFileRequest("Test123", testfile, false)); + request.setCommitMessage("this is great"); + request.setAuthor(new Person("Arthur Dent", "dent@hitchhiker.com")); + + svnModifyCommand.execute(request); + + WorkingCopy workingCopy = workDirFactory.createWorkingCopy(context, null); + assertThat(new File(workingCopy.getWorkingRepository(), "Test123")).exists(); + } + + @Test + public void shouldThrowFileAlreadyExistsException() throws IOException { + File testfile = temporaryFolder.newFile("a.txt"); + + ModifyCommandRequest request = new ModifyCommandRequest(); + request.addRequest(new ModifyCommandRequest.CreateFileRequest("a.txt", testfile, false)); + request.setCommitMessage("this is great"); + request.setAuthor(new Person("Arthur Dent", "dent@hitchhiker.com")); + + assertThrows(AlreadyExistsException.class, () -> svnModifyCommand.execute(request)); + } + + @Test + public void shouldUpdateExistingFile() throws IOException { + File testfile = temporaryFolder.newFile("a.txt"); + + ModifyCommandRequest request = new ModifyCommandRequest(); + request.addRequest(new ModifyCommandRequest.CreateFileRequest("a.txt", testfile, true)); + request.setCommitMessage("this is great"); + request.setAuthor(new Person("Arthur Dent", "dent@hitchhiker.com")); + + svnModifyCommand.execute(request); + + WorkingCopy workingCopy = workDirFactory.createWorkingCopy(context, null); + assertThat(new File(workingCopy.getWorkingRepository(), "a.txt")).exists(); + assertThat(new File(workingCopy.getWorkingRepository(), "a.txt")).hasContent(""); + } +}