From 5b034f8d0286f6e01d5cf84e8fe0d3f6809e1ab4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Mon, 13 Apr 2020 12:22:13 +0200 Subject: [PATCH 01/29] Introduce cache layer for workdirs --- .../util/CacheSupportingWorkdirProvider.java | 42 +++++++++++ .../util/CachingAllWorkdirProvider.java | 72 +++++++++++++++++++ .../util/NoneCachingWorkdirProvider.java | 51 +++++++++++++ .../repository/util/SimpleWorkdirFactory.java | 47 ++++++++++-- .../scm/repository/util/WorkingCopy.java | 8 ++- .../util/SimpleWorkdirFactoryTest.java | 43 ++++++++++- .../spi/SimpleGitWorkdirFactory.java | 12 +++- .../repository/spi/GitMergeCommandTest.java | 3 +- .../spi/GitMergeCommand_Conflict_Test.java | 3 +- .../repository/spi/GitModifyCommandTest.java | 3 +- .../spi/GitModifyCommand_LFSTest.java | 3 +- ...ModifyCommand_withEmptyRepositoryTest.java | 3 +- .../spi/SimpleGitWorkdirFactoryTest.java | 13 ++-- .../spi/SimpleHgWorkdirFactory.java | 25 +++++-- .../repository/spi/HgBranchCommandTest.java | 5 +- .../repository/spi/HgModifyCommandTest.java | 5 +- .../spi/SimpleSvnWorkDirFactory.java | 12 +++- .../spi/SimpleSvnWorkDirFactoryTest.java | 11 +-- .../repository/spi/SvnModifyCommandTest.java | 3 +- .../modules/ApplicationModuleProvider.java | 3 +- .../scm/lifecycle/modules/WorkdirModule.java | 50 +++++++++++++ 21 files changed, 370 insertions(+), 47 deletions(-) create mode 100644 scm-core/src/main/java/sonia/scm/repository/util/CacheSupportingWorkdirProvider.java create mode 100644 scm-core/src/main/java/sonia/scm/repository/util/CachingAllWorkdirProvider.java create mode 100644 scm-core/src/main/java/sonia/scm/repository/util/NoneCachingWorkdirProvider.java create mode 100644 scm-webapp/src/main/java/sonia/scm/lifecycle/modules/WorkdirModule.java diff --git a/scm-core/src/main/java/sonia/scm/repository/util/CacheSupportingWorkdirProvider.java b/scm-core/src/main/java/sonia/scm/repository/util/CacheSupportingWorkdirProvider.java new file mode 100644 index 0000000000..e067d88f11 --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/repository/util/CacheSupportingWorkdirProvider.java @@ -0,0 +1,42 @@ +/* + * 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.repository.util; + +import sonia.scm.repository.Repository; + +import java.io.File; +import java.io.IOException; + +public interface CacheSupportingWorkdirProvider { + SimpleWorkdirFactory.ParentAndClone getWorkdir( + Repository scmRepository, + String requestedBranch, + C context, + SimpleWorkdirFactory.WorkdirInitializer initializer, + SimpleWorkdirFactory.WorkdirReclaimer reclaimer + ) throws IOException; + + boolean cache(Repository repository, File target) throws IOException; +} diff --git a/scm-core/src/main/java/sonia/scm/repository/util/CachingAllWorkdirProvider.java b/scm-core/src/main/java/sonia/scm/repository/util/CachingAllWorkdirProvider.java new file mode 100644 index 0000000000..ebb9b7a7c6 --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/repository/util/CachingAllWorkdirProvider.java @@ -0,0 +1,72 @@ +/* + * 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.repository.util; + +import sonia.scm.repository.Repository; +import sonia.scm.util.IOUtil; + +import javax.inject.Inject; +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +public class CachingAllWorkdirProvider implements CacheSupportingWorkdirProvider { + + private final Map workdirs = new HashMap<>(); + + private final WorkdirProvider workdirProvider; + + @Inject + public CachingAllWorkdirProvider(WorkdirProvider workdirProvider) { + this.workdirProvider = workdirProvider; + } + + @Override + public SimpleWorkdirFactory.ParentAndClone getWorkdir(Repository scmRepository, String requestedBranch, C context, SimpleWorkdirFactory.WorkdirInitializer initializer, SimpleWorkdirFactory.WorkdirReclaimer reclaimer) throws IOException { + String id = scmRepository.getId(); + if (workdirs.containsKey(id)) { + File existingWorkdir = workdirs.get(id); + try { + return reclaimer.reclaim(existingWorkdir); + } catch (SimpleWorkdirFactory.ReclaimFailedException e) { + workdirs.remove(id); + IOUtil.delete(existingWorkdir, true); + } + } + return createNewWorkdir(initializer, id); + } + + public SimpleWorkdirFactory.ParentAndClone createNewWorkdir(SimpleWorkdirFactory.WorkdirInitializer initializer, String id) throws IOException { + File newWorkdir = workdirProvider.createNewWorkdir(); + workdirs.put(id, newWorkdir); + return initializer.initialize(newWorkdir); + } + + @Override + public boolean cache(Repository repository, File target) { + return true; + } +} diff --git a/scm-core/src/main/java/sonia/scm/repository/util/NoneCachingWorkdirProvider.java b/scm-core/src/main/java/sonia/scm/repository/util/NoneCachingWorkdirProvider.java new file mode 100644 index 0000000000..b46c0dcdf3 --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/repository/util/NoneCachingWorkdirProvider.java @@ -0,0 +1,51 @@ +/* + * 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.repository.util; + +import sonia.scm.repository.Repository; + +import javax.inject.Inject; +import java.io.File; +import java.io.IOException; + +public class NoneCachingWorkdirProvider implements CacheSupportingWorkdirProvider { + + private final WorkdirProvider workdirProvider; + + @Inject + public NoneCachingWorkdirProvider(WorkdirProvider workdirProvider) { + this.workdirProvider = workdirProvider; + } + + @Override + public SimpleWorkdirFactory.ParentAndClone getWorkdir(Repository scmRepository, String requestedBranch, C context, SimpleWorkdirFactory.WorkdirInitializer initializer, SimpleWorkdirFactory.WorkdirReclaimer reclaimer) throws IOException { + return initializer.initialize(workdirProvider.createNewWorkdir()); + } + + @Override + public boolean cache(Repository repository, File target) { + return false; + } +} diff --git a/scm-core/src/main/java/sonia/scm/repository/util/SimpleWorkdirFactory.java b/scm-core/src/main/java/sonia/scm/repository/util/SimpleWorkdirFactory.java index 5aed4fad77..22a0662b21 100644 --- a/scm-core/src/main/java/sonia/scm/repository/util/SimpleWorkdirFactory.java +++ b/scm-core/src/main/java/sonia/scm/repository/util/SimpleWorkdirFactory.java @@ -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.util; import org.slf4j.Logger; @@ -36,23 +36,45 @@ public abstract class SimpleWorkdirFactory implements WorkdirFactory createWorkingCopy(C context, String initialBranch) { try { - File directory = workdirProvider.createNewWorkdir(); - ParentAndClone parentAndClone = cloneRepository(context, directory, initialBranch); - return new WorkingCopy<>(parentAndClone.getClone(), parentAndClone.getParent(), this::closeWorkdir, this::closeCentral, directory); + ParentAndClone parentAndClone = workdirProvider.getWorkdir( + getScmRepository(context), + initialBranch, + context, + newFolder -> cloneRepository(context, newFolder, initialBranch), + cachedFolder -> reclaimRepository(context, cachedFolder, initialBranch) + ); + return new WorkingCopy(parentAndClone.getClone(), parentAndClone.getParent(), this::closeWorkdir, this::closeCentral, parentAndClone.getDirectory()) { + @Override + public void delete() throws IOException { + if (!workdirProvider.cache(getScmRepository(context), getDirectory())) { + super.delete(); + } + } + }; } catch (IOException e) { throw new InternalRepositoryException(getScmRepository(context), "could not clone repository in temporary directory", e); } } + @FunctionalInterface + public interface WorkdirInitializer { + ParentAndClone initialize(File target) throws IOException; + } + + @FunctionalInterface + public interface WorkdirReclaimer { + ParentAndClone reclaim(File target) throws IOException, ReclaimFailedException; + } + protected abstract Repository getScmRepository(C context); @SuppressWarnings("squid:S00112") @@ -64,6 +86,8 @@ public abstract class SimpleWorkdirFactory implements WorkdirFactory cloneRepository(C context, File target, String initialBranch) throws IOException; + protected abstract ParentAndClone reclaimRepository(C context, File target, String initialBranch) throws IOException; + private void closeCentral(R repository) { try { closeRepository(repository); @@ -83,10 +107,12 @@ public abstract class SimpleWorkdirFactory implements WorkdirFactory { private final R parent; private final W clone; + private final File directory; - public ParentAndClone(R parent, W clone) { + public ParentAndClone(R parent, W clone, File directory) { this.parent = parent; this.clone = clone; + this.directory = directory; } public R getParent() { @@ -96,5 +122,12 @@ public abstract class SimpleWorkdirFactory implements WorkdirFactory implements AutoCloseable { try { cleanupWorkdir.accept(workingRepository); cleanupCentral.accept(centralRepository); - IOUtil.delete(directory); + delete(); } catch (IOException e) { LOG.warn("could not delete temporary workdir '{}'", directory, e); } } + + void delete() throws IOException { + IOUtil.delete(directory); + } } diff --git a/scm-core/src/test/java/sonia/scm/repository/util/SimpleWorkdirFactoryTest.java b/scm-core/src/test/java/sonia/scm/repository/util/SimpleWorkdirFactoryTest.java index 1e36307288..ce634ee6d2 100644 --- a/scm-core/src/test/java/sonia/scm/repository/util/SimpleWorkdirFactoryTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/util/SimpleWorkdirFactoryTest.java @@ -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.util; @@ -52,10 +52,25 @@ public class SimpleWorkdirFactoryTest { private String initialBranchForLastCloneCall; + private boolean workdirIsCached = false; + private File workdir; + @Before public void initFactory() throws IOException { WorkdirProvider workdirProvider = new WorkdirProvider(temporaryFolder.newFolder()); - simpleWorkdirFactory = new SimpleWorkdirFactory(workdirProvider) { + CacheSupportingWorkdirProvider configurableTestWorkdirProvider = new CacheSupportingWorkdirProvider() { + @Override + public SimpleWorkdirFactory.ParentAndClone getWorkdir(Repository scmRepository, String requestedBranch, C context, SimpleWorkdirFactory.WorkdirInitializer initializer, SimpleWorkdirFactory.WorkdirReclaimer reclaimer) throws IOException { + workdir = workdirProvider.createNewWorkdir(); + return initializer.initialize(workdir); + } + + @Override + public boolean cache(Repository repository, File target) { + return workdirIsCached; + } + }; + simpleWorkdirFactory = new SimpleWorkdirFactory(configurableTestWorkdirProvider) { @Override protected Repository getScmRepository(Context context) { return REPOSITORY; @@ -66,6 +81,11 @@ public class SimpleWorkdirFactoryTest { repository.close(); } + @Override + protected ParentAndClone reclaimRepository(Context context, File target, String initialBranch) throws IOException { + throw new UnsupportedOperationException(); + } + @Override protected void closeWorkdirInternal(Closeable workdir) throws Exception { workdir.close(); @@ -74,7 +94,7 @@ public class SimpleWorkdirFactoryTest { @Override protected ParentAndClone cloneRepository(Context context, File target, String initialBranch) { initialBranchForLastCloneCall = initialBranch; - return new ParentAndClone<>(parent, clone); + return new ParentAndClone<>(parent, clone, target); } }; } @@ -104,6 +124,23 @@ public class SimpleWorkdirFactoryTest { verify(clone).close(); } + @Test + public void shouldDeleteWorkdirIfNotCached() { + Context context = new Context(); + try (WorkingCopy workingCopy = simpleWorkdirFactory.createWorkingCopy(context, null)) {} + + assertThat(workdir).doesNotExist(); + } + + @Test + public void shouldNotDeleteWorkdirIfCached() { + Context context = new Context(); + workdirIsCached = true; + try (WorkingCopy workingCopy = simpleWorkdirFactory.createWorkingCopy(context, null)) {} + + assertThat(workdir).exists(); + } + @Test public void shouldPropagateInitialBranch() { Context context = new Context(); diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/SimpleGitWorkdirFactory.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/SimpleGitWorkdirFactory.java index ff0101f297..6c72e58ec8 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/SimpleGitWorkdirFactory.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/SimpleGitWorkdirFactory.java @@ -30,10 +30,11 @@ import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.transport.ScmTransportProtocol; +import sonia.scm.repository.GitUtil; import sonia.scm.repository.GitWorkdirFactory; import sonia.scm.repository.InternalRepositoryException; +import sonia.scm.repository.util.CacheSupportingWorkdirProvider; import sonia.scm.repository.util.SimpleWorkdirFactory; -import sonia.scm.repository.util.WorkdirProvider; import sonia.scm.util.SystemUtil; import javax.inject.Inject; @@ -46,7 +47,7 @@ import static sonia.scm.NotFoundException.notFound; public class SimpleGitWorkdirFactory extends SimpleWorkdirFactory implements GitWorkdirFactory { @Inject - public SimpleGitWorkdirFactory(WorkdirProvider workdirProvider) { + public SimpleGitWorkdirFactory(CacheSupportingWorkdirProvider workdirProvider) { super(workdirProvider); } @@ -66,12 +67,17 @@ public class SimpleGitWorkdirFactory extends SimpleWorkdirFactory(null, clone); + return new ParentAndClone<>(null, clone, target); } catch (GitAPIException | IOException e) { throw new InternalRepositoryException(context.getRepository(), "could not clone working copy of repository", e); } } + @Override + protected ParentAndClone reclaimRepository(GitContext context, File target, String initialBranch) throws IOException { + return new ParentAndClone<>(null, GitUtil.open(target), target); + } + private String createScmTransportProtocolUri(File bareRepository) { if (SystemUtil.isWindows()) { return ScmTransportProtocol.NAME + ":///" + bareRepository.getAbsolutePath().replaceAll("\\\\", "/"); diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitMergeCommandTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitMergeCommandTest.java index ed21f683fb..8e3524dc9a 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitMergeCommandTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitMergeCommandTest.java @@ -44,6 +44,7 @@ import sonia.scm.repository.GitWorkdirFactory; import sonia.scm.repository.Person; import sonia.scm.repository.api.MergeCommandResult; import sonia.scm.repository.api.MergeStrategy; +import sonia.scm.repository.util.NoneCachingWorkdirProvider; import sonia.scm.repository.util.WorkdirProvider; import sonia.scm.user.User; @@ -424,7 +425,7 @@ public class GitMergeCommandTest extends AbstractGitCommandTestBase { } private GitMergeCommand createCommand(Consumer interceptor) { - return new GitMergeCommand(createContext(), new SimpleGitWorkdirFactory(new WorkdirProvider())) { + return new GitMergeCommand(createContext(), new SimpleGitWorkdirFactory(new NoneCachingWorkdirProvider(new WorkdirProvider()))) { @Override > R inClone(Function workerSupplier, GitWorkdirFactory workdirFactory, String initialBranch) { Function interceptedWorkerSupplier = git -> { diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitMergeCommand_Conflict_Test.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitMergeCommand_Conflict_Test.java index 391ac2d762..fc0a457a29 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitMergeCommand_Conflict_Test.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitMergeCommand_Conflict_Test.java @@ -27,6 +27,7 @@ package sonia.scm.repository.spi; import org.junit.Rule; import org.junit.Test; import sonia.scm.repository.spi.MergeConflictResult.SingleMergeConflict; +import sonia.scm.repository.util.NoneCachingWorkdirProvider; import sonia.scm.repository.util.WorkdirProvider; import java.io.IOException; @@ -91,7 +92,7 @@ public class GitMergeCommand_Conflict_Test extends AbstractGitCommandTestBase { } private MergeConflictResult computeMergeConflictResult(String branchToMerge, String targetBranch) { - GitMergeCommand gitMergeCommand = new GitMergeCommand(createContext(), new SimpleGitWorkdirFactory(new WorkdirProvider())); + GitMergeCommand gitMergeCommand = new GitMergeCommand(createContext(), new SimpleGitWorkdirFactory(new NoneCachingWorkdirProvider(new WorkdirProvider()))); MergeCommandRequest mergeCommandRequest = new MergeCommandRequest(); mergeCommandRequest.setBranchToMerge(branchToMerge); mergeCommandRequest.setTargetBranch(targetBranch); diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommandTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommandTest.java index 746f05f61c..2f53b25a71 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommandTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommandTest.java @@ -42,6 +42,7 @@ import sonia.scm.BadRequestException; import sonia.scm.ConcurrentModificationException; import sonia.scm.NotFoundException; import sonia.scm.repository.Person; +import sonia.scm.repository.util.NoneCachingWorkdirProvider; import sonia.scm.repository.util.WorkdirProvider; import sonia.scm.web.lfs.LfsBlobStoreFactory; @@ -323,7 +324,7 @@ public class GitModifyCommandTest extends AbstractGitCommandTestBase { } private GitModifyCommand createCommand() { - return new GitModifyCommand(createContext(), new SimpleGitWorkdirFactory(new WorkdirProvider()), lfsBlobStoreFactory); + return new GitModifyCommand(createContext(), new SimpleGitWorkdirFactory(new NoneCachingWorkdirProvider(new WorkdirProvider())), lfsBlobStoreFactory); } @FunctionalInterface diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_LFSTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_LFSTest.java index bdad922b01..293c251a23 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_LFSTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_LFSTest.java @@ -35,6 +35,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import sonia.scm.repository.Person; +import sonia.scm.repository.util.NoneCachingWorkdirProvider; import sonia.scm.repository.util.WorkdirProvider; import sonia.scm.store.Blob; import sonia.scm.store.BlobStore; @@ -130,7 +131,7 @@ public class GitModifyCommand_LFSTest extends AbstractGitCommandTestBase { } private GitModifyCommand createCommand() { - return new GitModifyCommand(createContext(), new SimpleGitWorkdirFactory(new WorkdirProvider()), lfsBlobStoreFactory); + return new GitModifyCommand(createContext(), new SimpleGitWorkdirFactory(new NoneCachingWorkdirProvider(new WorkdirProvider())), lfsBlobStoreFactory); } @Override diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_withEmptyRepositoryTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_withEmptyRepositoryTest.java index ae1c2fd854..e339817d0d 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_withEmptyRepositoryTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_withEmptyRepositoryTest.java @@ -38,6 +38,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import sonia.scm.repository.Person; +import sonia.scm.repository.util.NoneCachingWorkdirProvider; import sonia.scm.repository.util.WorkdirProvider; import sonia.scm.web.lfs.LfsBlobStoreFactory; @@ -101,7 +102,7 @@ public class GitModifyCommand_withEmptyRepositoryTest extends AbstractGitCommand } private GitModifyCommand createCommand() { - return new GitModifyCommand(createContext(), new SimpleGitWorkdirFactory(new WorkdirProvider()), lfsBlobStoreFactory); + return new GitModifyCommand(createContext(), new SimpleGitWorkdirFactory(new NoneCachingWorkdirProvider(new WorkdirProvider())), lfsBlobStoreFactory); } @FunctionalInterface diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/SimpleGitWorkdirFactoryTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/SimpleGitWorkdirFactoryTest.java index 4d76a4952d..aa24f33a87 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/SimpleGitWorkdirFactoryTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/SimpleGitWorkdirFactoryTest.java @@ -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; import org.eclipse.jgit.lib.Repository; @@ -35,6 +35,7 @@ import sonia.scm.repository.GitRepositoryHandler; import sonia.scm.repository.PreProcessorUtil; import sonia.scm.repository.RepositoryManager; import sonia.scm.repository.api.HookContextFactory; +import sonia.scm.repository.util.NoneCachingWorkdirProvider; import sonia.scm.repository.util.WorkdirProvider; import sonia.scm.repository.util.WorkingCopy; @@ -66,7 +67,7 @@ public class SimpleGitWorkdirFactoryTest extends AbstractGitCommandTestBase { @Test public void emptyPoolShouldCreateNewWorkdir() { - SimpleGitWorkdirFactory factory = new SimpleGitWorkdirFactory(workdirProvider); + SimpleGitWorkdirFactory factory = new SimpleGitWorkdirFactory(new NoneCachingWorkdirProvider(workdirProvider)); File masterRepo = createRepositoryDirectory(); try (WorkingCopy workingCopy = factory.createWorkingCopy(createContext(), null)) { @@ -84,7 +85,7 @@ public class SimpleGitWorkdirFactoryTest extends AbstractGitCommandTestBase { @Test public void shouldCheckoutInitialBranch() { - SimpleGitWorkdirFactory factory = new SimpleGitWorkdirFactory(workdirProvider); + SimpleGitWorkdirFactory factory = new SimpleGitWorkdirFactory(new NoneCachingWorkdirProvider(workdirProvider)); try (WorkingCopy workingCopy = factory.createWorkingCopy(createContext(), "test-branch")) { assertThat(new File(workingCopy.getWorkingRepository().getWorkTree(), "a.txt")) @@ -96,7 +97,7 @@ public class SimpleGitWorkdirFactoryTest extends AbstractGitCommandTestBase { @Test public void shouldCheckoutDefaultBranch() { - SimpleGitWorkdirFactory factory = new SimpleGitWorkdirFactory(workdirProvider); + SimpleGitWorkdirFactory factory = new SimpleGitWorkdirFactory(new NoneCachingWorkdirProvider(workdirProvider)); try (WorkingCopy workingCopy = factory.createWorkingCopy(createContext(), null)) { assertThat(new File(workingCopy.getWorkingRepository().getWorkTree(), "a.txt")) @@ -108,7 +109,7 @@ public class SimpleGitWorkdirFactoryTest extends AbstractGitCommandTestBase { @Test public void cloneFromPoolShouldNotBeReused() { - SimpleGitWorkdirFactory factory = new SimpleGitWorkdirFactory(workdirProvider); + SimpleGitWorkdirFactory factory = new SimpleGitWorkdirFactory(new NoneCachingWorkdirProvider(workdirProvider)); File firstDirectory; try (WorkingCopy workingCopy = factory.createWorkingCopy(createContext(), null)) { @@ -122,7 +123,7 @@ public class SimpleGitWorkdirFactoryTest extends AbstractGitCommandTestBase { @Test public void cloneFromPoolShouldBeDeletedOnClose() { - SimpleGitWorkdirFactory factory = new SimpleGitWorkdirFactory(workdirProvider); + SimpleGitWorkdirFactory factory = new SimpleGitWorkdirFactory(new NoneCachingWorkdirProvider(workdirProvider)); File directory; try (WorkingCopy workingCopy = factory.createWorkingCopy(createContext(), null)) { diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkdirFactory.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkdirFactory.java index 5a25aa247d..99c02d6af8 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkdirFactory.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkdirFactory.java @@ -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; import com.aragost.javahg.BaseRepository; @@ -29,8 +29,8 @@ 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.CacheSupportingWorkdirProvider; import sonia.scm.repository.util.SimpleWorkdirFactory; -import sonia.scm.repository.util.WorkdirProvider; import sonia.scm.web.HgRepositoryEnvironmentBuilder; import javax.inject.Inject; @@ -45,15 +45,13 @@ public class SimpleHgWorkdirFactory extends SimpleWorkdirFactory hgRepositoryEnvironmentBuilder; @Inject - public SimpleHgWorkdirFactory(Provider hgRepositoryEnvironmentBuilder, WorkdirProvider workdirProvider) { + public SimpleHgWorkdirFactory(Provider hgRepositoryEnvironmentBuilder, CacheSupportingWorkdirProvider workdirProvider) { super(workdirProvider); this.hgRepositoryEnvironmentBuilder = hgRepositoryEnvironmentBuilder; } @Override public ParentAndClone cloneRepository(HgCommandContext context, File target, String initialBranch) throws IOException { - BiConsumer> repositoryMapBiConsumer = - (repository, environment) -> hgRepositoryEnvironmentBuilder.get().buildFor(repository, null, environment); - Repository centralRepository = context.openWithSpecialEnvironment(repositoryMapBiConsumer); + Repository centralRepository = openCentral(context); CloneCommand cloneCommand = CloneCommandFlags.on(centralRepository); if (initialBranch != null) { cloneCommand.updaterev(initialBranch); @@ -62,7 +60,20 @@ public class SimpleHgWorkdirFactory extends SimpleWorkdirFactory(centralRepository, clone); + return new ParentAndClone<>(centralRepository, clone, target); + } + + public Repository openCentral(HgCommandContext context) { + BiConsumer> repositoryMapBiConsumer = + (repository, environment) -> hgRepositoryEnvironmentBuilder.get().buildFor(repository, null, environment); + return context.openWithSpecialEnvironment(repositoryMapBiConsumer); + } + + @Override + protected ParentAndClone reclaimRepository(HgCommandContext context, File target, String initialBranch) throws IOException { + Repository centralRepository = openCentral(context); + BaseRepository clone = Repository.open(target); + return new ParentAndClone<>(centralRepository, clone, target); } @Override diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgBranchCommandTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgBranchCommandTest.java index 1d7f0ca627..eab4749b61 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgBranchCommandTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgBranchCommandTest.java @@ -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; import com.aragost.javahg.commands.PullCommand; @@ -32,6 +32,7 @@ import sonia.scm.repository.Branch; import sonia.scm.repository.HgTestUtil; import sonia.scm.repository.InternalRepositoryException; import sonia.scm.repository.api.BranchRequest; +import sonia.scm.repository.util.NoneCachingWorkdirProvider; import sonia.scm.repository.util.WorkdirProvider; import sonia.scm.web.HgRepositoryEnvironmentBuilder; @@ -49,7 +50,7 @@ public class HgBranchCommandTest extends AbstractHgCommandTestBase { HgRepositoryEnvironmentBuilder hgRepositoryEnvironmentBuilder = new HgRepositoryEnvironmentBuilder(handler, HgTestUtil.createHookManager()); - workdirFactory = new SimpleHgWorkdirFactory(Providers.of(hgRepositoryEnvironmentBuilder), new WorkdirProvider()) { + workdirFactory = new SimpleHgWorkdirFactory(Providers.of(hgRepositoryEnvironmentBuilder), new NoneCachingWorkdirProvider(new WorkdirProvider())) { @Override public void configure(PullCommand pullCommand) { // we do not want to configure http hooks in this unit test diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgModifyCommandTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgModifyCommandTest.java index 1a944f0681..6cbc647447 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgModifyCommandTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgModifyCommandTest.java @@ -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; import com.google.inject.util.Providers; @@ -35,6 +35,7 @@ import sonia.scm.NotFoundException; import sonia.scm.repository.HgHookManager; import sonia.scm.repository.HgTestUtil; import sonia.scm.repository.Person; +import sonia.scm.repository.util.NoneCachingWorkdirProvider; import sonia.scm.repository.util.WorkdirProvider; import sonia.scm.web.HgRepositoryEnvironmentBuilder; @@ -55,7 +56,7 @@ public class HgModifyCommandTest extends AbstractHgCommandTestBase { public void initHgModifyCommand() { HgHookManager hookManager = HgTestUtil.createHookManager(); HgRepositoryEnvironmentBuilder environmentBuilder = new HgRepositoryEnvironmentBuilder(handler, hookManager); - SimpleHgWorkdirFactory workdirFactory = new SimpleHgWorkdirFactory(Providers.of(environmentBuilder), new WorkdirProvider()) { + SimpleHgWorkdirFactory workdirFactory = new SimpleHgWorkdirFactory(Providers.of(environmentBuilder), new NoneCachingWorkdirProvider(new WorkdirProvider())) { @Override public void configure(com.aragost.javahg.commands.PullCommand pullCommand) { // we do not want to configure http hooks in this unit test 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 dcd06f9207..9c8bcfe987 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 @@ -32,16 +32,17 @@ import org.tmatesoft.svn.core.wc2.SvnTarget; import sonia.scm.repository.InternalRepositoryException; import sonia.scm.repository.Repository; import sonia.scm.repository.SvnWorkDirFactory; +import sonia.scm.repository.util.CacheSupportingWorkdirProvider; import sonia.scm.repository.util.SimpleWorkdirFactory; -import sonia.scm.repository.util.WorkdirProvider; import javax.inject.Inject; import java.io.File; +import java.io.IOException; public class SimpleSvnWorkDirFactory extends SimpleWorkdirFactory implements SvnWorkDirFactory { @Inject - public SimpleSvnWorkDirFactory(WorkdirProvider workdirProvider) { + public SimpleSvnWorkDirFactory(CacheSupportingWorkdirProvider workdirProvider) { super(workdirProvider); } @@ -73,7 +74,12 @@ public class SimpleSvnWorkDirFactory extends SimpleWorkdirFactory(context.getDirectory(), workingCopy); + return new ParentAndClone<>(context.getDirectory(), workingCopy, workingCopy); + } + + @Override + protected ParentAndClone reclaimRepository(SvnContext context, File target, String initialBranch) throws IOException { + return new ParentAndClone<>(context.getDirectory(), target, target); } @Override diff --git a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SimpleSvnWorkDirFactoryTest.java b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SimpleSvnWorkDirFactoryTest.java index a21a0319e6..8f1f7b00c9 100644 --- a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SimpleSvnWorkDirFactoryTest.java +++ b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SimpleSvnWorkDirFactoryTest.java @@ -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; import org.junit.Before; @@ -30,6 +30,7 @@ import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.tmatesoft.svn.core.SVNException; import sonia.scm.repository.Repository; +import sonia.scm.repository.util.NoneCachingWorkdirProvider; import sonia.scm.repository.util.WorkdirProvider; import sonia.scm.repository.util.WorkingCopy; @@ -53,7 +54,7 @@ public class SimpleSvnWorkDirFactoryTest extends AbstractSvnCommandTestBase { @Test public void shouldCheckoutLatestRevision() throws SVNException, IOException { - SimpleSvnWorkDirFactory factory = new SimpleSvnWorkDirFactory(workdirProvider); + SimpleSvnWorkDirFactory factory = new SimpleSvnWorkDirFactory(new NoneCachingWorkdirProvider(workdirProvider)); try (WorkingCopy workingCopy = factory.createWorkingCopy(createContext(), null)) { assertThat(new File(workingCopy.getWorkingRepository(), "a.txt")) @@ -65,7 +66,7 @@ public class SimpleSvnWorkDirFactoryTest extends AbstractSvnCommandTestBase { @Test public void cloneFromPoolshouldNotBeReused() { - SimpleSvnWorkDirFactory factory = new SimpleSvnWorkDirFactory(workdirProvider); + SimpleSvnWorkDirFactory factory = new SimpleSvnWorkDirFactory(new NoneCachingWorkdirProvider(workdirProvider)); File firstDirectory; try (WorkingCopy workingCopy = factory.createWorkingCopy(createContext(), null)) { @@ -79,7 +80,7 @@ public class SimpleSvnWorkDirFactoryTest extends AbstractSvnCommandTestBase { @Test public void shouldDeleteCloneOnClose() { - SimpleSvnWorkDirFactory factory = new SimpleSvnWorkDirFactory(workdirProvider); + SimpleSvnWorkDirFactory factory = new SimpleSvnWorkDirFactory(new NoneCachingWorkdirProvider(workdirProvider)); File directory; File workingRepository; @@ -94,7 +95,7 @@ public class SimpleSvnWorkDirFactoryTest extends AbstractSvnCommandTestBase { @Test public void shouldReturnRepository() { - SimpleSvnWorkDirFactory factory = new SimpleSvnWorkDirFactory(workdirProvider); + SimpleSvnWorkDirFactory factory = new SimpleSvnWorkDirFactory(new NoneCachingWorkdirProvider(workdirProvider)); Repository scmRepository = factory.getScmRepository(createContext()); assertThat(scmRepository).isSameAs(repository); } 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 index 533e012dc3..4060060ed8 100644 --- 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 @@ -33,6 +33,7 @@ import org.junit.Test; import org.junit.rules.TemporaryFolder; import sonia.scm.AlreadyExistsException; import sonia.scm.repository.Person; +import sonia.scm.repository.util.NoneCachingWorkdirProvider; import sonia.scm.repository.util.WorkdirProvider; import sonia.scm.repository.util.WorkingCopy; @@ -56,7 +57,7 @@ public class SvnModifyCommandTest extends AbstractSvnCommandTestBase { @Before public void initSvnModifyCommand() { context = createContext(); - workDirFactory = new SimpleSvnWorkDirFactory(new WorkdirProvider(context.getDirectory())); + workDirFactory = new SimpleSvnWorkDirFactory(new NoneCachingWorkdirProvider(new WorkdirProvider(context.getDirectory()))); svnModifyCommand = new SvnModifyCommand(context, workDirFactory); } diff --git a/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/ApplicationModuleProvider.java b/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/ApplicationModuleProvider.java index 4b65f9094a..b34610f8ce 100644 --- a/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/ApplicationModuleProvider.java +++ b/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/ApplicationModuleProvider.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.lifecycle.modules; import com.google.common.base.Throwables; @@ -77,6 +77,7 @@ public class ApplicationModuleProvider implements ModuleProvider { } moduleList.add(new MapperModule()); moduleList.add(new ExecutorModule()); + moduleList.add(new WorkdirModule(pluginLoader)); return moduleList; } diff --git a/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/WorkdirModule.java b/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/WorkdirModule.java new file mode 100644 index 0000000000..1f7e72ee9c --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/WorkdirModule.java @@ -0,0 +1,50 @@ +/* + * 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.lifecycle.modules; + +import com.google.inject.AbstractModule; +import sonia.scm.plugin.PluginLoader; +import sonia.scm.repository.util.CacheSupportingWorkdirProvider; + +public class WorkdirModule extends AbstractModule { + public static final String DEFAULT_WORKDIR_CACHE_STRATEGY = "sonia.scm.repository.util.NoneCachingWorkdirProvider"; + public static final String WORKDIR_CACHE_STRATEGY_PROPERTY = "scm.workdirCacheStrategy"; + private final PluginLoader pluginLoader; + + public WorkdirModule(PluginLoader pluginLoader) { + this.pluginLoader = pluginLoader; + } + + @Override + protected void configure() { + try { + String workdirCacheStrategy = System.getProperty(WORKDIR_CACHE_STRATEGY_PROPERTY, DEFAULT_WORKDIR_CACHE_STRATEGY); + Class strategyClass = (Class) pluginLoader.getUberClassLoader().loadClass(workdirCacheStrategy); + bind(CacheSupportingWorkdirProvider.class).to(strategyClass); + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} From 7e89a0c1c0b7c15a392476e60f01d233edee147a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Mon, 13 Apr 2020 14:39:02 +0200 Subject: [PATCH 02/29] Update repositories in reclaim --- .../repository/util/SimpleWorkdirFactory.java | 8 ++++- .../spi/SimpleGitWorkdirFactory.java | 32 +++++++++++++++++-- .../spi/SimpleHgWorkdirFactory.java | 2 ++ .../spi/SimpleSvnWorkDirFactory.java | 13 +++++++- 4 files changed, 51 insertions(+), 4 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/repository/util/SimpleWorkdirFactory.java b/scm-core/src/main/java/sonia/scm/repository/util/SimpleWorkdirFactory.java index 22a0662b21..539dcac116 100644 --- a/scm-core/src/main/java/sonia/scm/repository/util/SimpleWorkdirFactory.java +++ b/scm-core/src/main/java/sonia/scm/repository/util/SimpleWorkdirFactory.java @@ -86,7 +86,7 @@ public abstract class SimpleWorkdirFactory implements WorkdirFactory cloneRepository(C context, File target, String initialBranch) throws IOException; - protected abstract ParentAndClone reclaimRepository(C context, File target, String initialBranch) throws IOException; + protected abstract ParentAndClone reclaimRepository(C context, File target, String initialBranch) throws IOException, ReclaimFailedException; private void closeCentral(R repository) { try { @@ -129,5 +129,11 @@ public abstract class SimpleWorkdirFactory implements WorkdirFactory implements GitWorkdirFactory { + private static final Logger LOG = LoggerFactory.getLogger(SimpleGitWorkdirFactory.class); + @Inject public SimpleGitWorkdirFactory(CacheSupportingWorkdirProvider workdirProvider) { super(workdirProvider); @@ -53,6 +58,8 @@ public class SimpleGitWorkdirFactory extends SimpleWorkdirFactory cloneRepository(GitContext context, File target, String initialBranch) { + LOG.trace("clone repository {}", context.getRepository().getId()); + long start = System.nanoTime(); try { Repository clone = Git.cloneRepository() .setURI(createScmTransportProtocolUri(context.getDirectory())) @@ -70,12 +77,33 @@ public class SimpleGitWorkdirFactory extends SimpleWorkdirFactory(null, clone, target); } catch (GitAPIException | IOException e) { throw new InternalRepositoryException(context.getRepository(), "could not clone working copy of repository", e); + } finally { + long end = System.nanoTime(); + long duration = end - start; + LOG.trace("took {} ns to clone repository {}", duration, context.getRepository().getId()); } } @Override - protected ParentAndClone reclaimRepository(GitContext context, File target, String initialBranch) throws IOException { - return new ParentAndClone<>(null, GitUtil.open(target), target); + protected ParentAndClone reclaimRepository(GitContext context, File target, String initialBranch) throws IOException, ReclaimFailedException { + LOG.trace("reclaim repository {}", context.getRepository().getId()); + long start = System.nanoTime(); + Repository repo = GitUtil.open(target); + try (Git git = Git.open(target)) { + git.reset().setMode(ResetCommand.ResetType.HARD).call(); + git.clean().setForce(true).setCleanDirectories(true).call(); + git.fetch().call(); + git.branchDelete().setBranchNames(initialBranch).setForce(true).call(); + git.checkout().setForced(true).setName("origin/" + initialBranch).call(); + git.checkout().setName(initialBranch).setCreateBranch(true).call(); + return new ParentAndClone<>(null, repo, target); + } catch (GitAPIException e) { + throw new ReclaimFailedException(e); + } finally { + long end = System.nanoTime(); + long duration = end - start; + LOG.trace("took {} ns to reclaim repository {}\n", duration, context.getRepository().getId()); + } } private String createScmTransportProtocolUri(File bareRepository) { diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkdirFactory.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkdirFactory.java index 99c02d6af8..5663ab355e 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkdirFactory.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkdirFactory.java @@ -28,6 +28,7 @@ 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.UpdateCommand; import com.aragost.javahg.commands.flags.CloneCommandFlags; import sonia.scm.repository.util.CacheSupportingWorkdirProvider; import sonia.scm.repository.util.SimpleWorkdirFactory; @@ -73,6 +74,7 @@ public class SimpleHgWorkdirFactory extends SimpleWorkdirFactory reclaimRepository(HgCommandContext context, File target, String initialBranch) throws IOException { Repository centralRepository = openCentral(context); BaseRepository clone = Repository.open(target); + UpdateCommand.on(clone).rev(initialBranch).execute(); return new ParentAndClone<>(centralRepository, clone, target); } 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 9c8bcfe987..3d88d79388 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 @@ -24,8 +24,12 @@ package sonia.scm.repository.spi; +import org.tmatesoft.svn.core.SVNDepth; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNURL; +import org.tmatesoft.svn.core.wc.SVNClientManager; +import org.tmatesoft.svn.core.wc.SVNRevision; +import org.tmatesoft.svn.core.wc.SVNWCClient; import org.tmatesoft.svn.core.wc2.SvnCheckout; import org.tmatesoft.svn.core.wc2.SvnOperationFactory; import org.tmatesoft.svn.core.wc2.SvnTarget; @@ -78,7 +82,14 @@ public class SimpleSvnWorkDirFactory extends SimpleWorkdirFactory reclaimRepository(SvnContext context, File target, String initialBranch) throws IOException { + protected ParentAndClone reclaimRepository(SvnContext context, File target, String initialBranch) throws ReclaimFailedException { + SVNClientManager clientManager = SVNClientManager.newInstance(); + try { + clientManager.getWCClient().doCleanup(target); + clientManager.getUpdateClient().doUpdate(target, SVNRevision.HEAD, SVNDepth.fromRecurse(true), false, false); + } catch (SVNException e) { + throw new ReclaimFailedException(e); + } return new ParentAndClone<>(context.getDirectory(), target, target); } From e5f4ad72d66fd4f3dca607182ac0f7d8ae9fe9fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Sat, 18 Apr 2020 14:31:32 +0200 Subject: [PATCH 03/29] Add test for git reclaim of workdir --- .../spi/SimpleGitWorkdirFactory.java | 4 +- .../spi/SimpleGitWorkdirFactoryTest.java | 86 ++++++++++++++++++ .../spi/scm-git-spi-test-workdir.zip | Bin 0 -> 40348 bytes 3 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 scm-plugins/scm-git-plugin/src/test/resources/sonia/scm/repository/spi/scm-git-spi-test-workdir.zip diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/SimpleGitWorkdirFactory.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/SimpleGitWorkdirFactory.java index aeb2575797..e75b8775cc 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/SimpleGitWorkdirFactory.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/SimpleGitWorkdirFactory.java @@ -93,8 +93,8 @@ public class SimpleGitWorkdirFactory extends SimpleWorkdirFactory(null, repo, target); } catch (GitAPIException e) { @@ -106,7 +106,7 @@ public class SimpleGitWorkdirFactory extends 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≶S=I{6(jO3u*sfb=2PO+1vQU-(HbMcA5NIIs2SGqY zI37q`F+?D3MS-D2A{fXDU_eNSf&vBTEu(4zjCcG}pSFm_ssqEJOimQoZ={gsy~y(p zG35cACas^i4Qv2{!4lDUz>VR6ZYds#Kmv9g3=B39z+f;b6F|ZVK<(m-^pNJgejR}V zMPEuV3w7y3(bLYL7_*ZgAvI8)|LExwMxJ(tfemQH=-y6ay_VQw#|4dtBZXCzLE{v; z(K@Ubqy*KL>kg#ke?NHCu%s1msP0l$@J;zo_TXErTJpazFW6H z?UsGouUHxKV7FKG9>!$(bMMXlT5r9m>VZ^<^9V$ii@IKqtuV_AbF&jFQ;6DSAV`Wrv!wfVk}e-{(vIbc7p*@!z8d@ zmM;gOhO~a72tWeF6>tLxU|JAp!=cbXC^6Oqf zqz>ubl_M4_?4?|qi2{QPyQrPVcM2ukWJK(US^8}BwEE0~WS#WOI4q^;P&xKo9EtW@7AjSvNJ z7DfQV6(j);)U>w}!x^9#^UIiXOJc0lj{|dU`lPwi12I&nKOhLU-7*wO1uW8Evi`QQ z0U!Zo4WQx#!=NE}IE+BR0dpugKpjv(PZ|b+Bk*uwpbxRtVf(EL{JOF6f3Z^c`$-Ej z)3b<~Z@eSb-DQ-mPX4y(3Q&xLk}@&`6iCc)z{DpSiO1v7Ksya+FCq~TU~mix0ui@{ zf=P9E<=;;4ZNKT7Lsu`CYP|l*c3|vq+D`Y!!_&Q@4t^3<8^@Nme;ME8o$m z=2V$68i{E<9Y1AK)_%d&@%uYoU7e22x#6MLn!#opRqpxGq|?aDC)9p3Ubs|!$R>y3jtKP+Ib6m+hsmizKoF?{m zw)G-q`wI=vKj1p*PZaUq2>0x;zO zCBOj^0McMMG%!;Q6jPBvK8Hghaa*=h_jii66+=OQ@q5jlUU7|Xaea01j$T7`G0iTm zo^cAYD@Hs2q>4q{?um^8RpQd?mp=3Yw2{_N^Z`iQd$sJ#iAgj6rb_JCa~J5#vjR(ta-%k=;+)_j|B~@C&WYKA3BPsl<}TCO=$xWRm<#- zGks#q^o%zUO>0lJOj!zn z+P6nnj+^7E_cSe@s64&YWk0cRB8|R5bYFjzv{@%phxG}QQ-L3;Cq#`j|3J|2+wG*1 z`gpdJe)!)8JpdA(NWfuuw5*5b`Miff6Q{m zLj@fCMl|H5gjyN=QDPEttOS`+cj~^ck~l~9j7>R9#)Oj5@Z%v`HdC#G2PO`vE+(1_ zxa3Eu1?xV(RMW9z;T`?doPgA;yuv5WuTQKll0Ttlqg+*RQHs2gy1Jh7?zBd^@4EI! z`dc*B3&+I%fWPSN3Ob3u7xF!te_LS!kl;Y}3Iht7Xebzo#sJv}kbw|jL^K-6Xn`qT zI1-ruM{kv6e%mMAQe>QZr-Yakslr4>CGrR4fVW#KA%#52m{HyvfXYdEe(slgC;UC{gr2qQ1l#R2q zz57=1u&tL8S^2ERE&$($LEJ$GK>YRn3|k;BZUjl3v!kP}hm)n}a=PRWGda`bgU1ev%1VWAEZ1h@y~$T~ z*e`i6)SmIScILEy%~>qf6Am?#dCv9Ji_u_i;|i9?;i|}~C$2>g{Flp*;`h&#FTCG` z8_bM6%xNY@F^E5fIoSAKpJ~lmbkaPNWapOZF}x&smwig5_d~Jf+*<26xPH8ydv*xP zl!_g=sa7lIsxUEZUb$~h-P_`=MUf1+d{5>x&|^CEfxsi=Tkv=j{hBs$z_nbKe=O66oKay*)j?CJ|Dkcyj&l>+1D8r_Xjt1iNS5x7}Me*ynyI zS~q>_)MbH*$f)dc+~UC94ySv5bH1^!BHkOj8Xw!xMIdMof6U^&%^EwwGD%(UqJdoD zS~%duarWX6T*mNlSx^q0xW}cG_9E|RiD?a=sf%j@Yx2k^>78M=)~CKtL2_?nwM_l5^D$7rr?%pm7xk(Rinrr?%iuJmKpW@k z;!qOlk9BDmPE4(5#cMjx+lYl9ouRil5k_HuRBXrC{<}wbkBHbX z3uRBFh!Y!Jn1yKFZmr7y$O;%)NT89s!DcOra8EhA$jr0*%ZHxFZwi7An7Xch0-*$9NF7q1ySz`p$w#7C+*-meGJle=CiF%9rY%IzzMkVup_MH)T|bizQB+ zNd-E0YAZHt)8;IOEl}!l*VVxl){{vI&P45%r+A^4D!Gct=>av3b#e0o$kCg}E@izq zahrihwN$(1QrQ)4O~SPacZfr}X#0bhJ1{vew_S=&lAVw}J#=(jje0#esnm}?EzjGc z5sg{R?^;gp+~pfQs8VuJIHe?_xMR|9-=|jpD&xK`;yvuKbiV7mRFZ>6G=dHpuooD+ zE70v1_R7Nxa++LxN<%Mxb3d6uQX(a4Z*}Eqq9!3(V_?+gN!DnV+?coL{*sHt7R%^MzTaEnoP>Q2vJ_yd0?KuaqSRyAw}_V z_si_LiXi)xE4Pa(QlihhUfKJeeJYtJ9e*4;JLFHM=9~6PyLHC>=}P4%^AM{Z!bG1u zvu4lLj<>f(4jm5Kxm&eelKD05folyXXMztF3QKa=oPeNnwbl9K;1I?$T$uB_+dr{A zyoxywS$r+fsQH%piVLNO=p_Nl%YA9E&qpu|S9MpIz0>@dXFAJO4+Jt@GKlL=iBPM% z!mnlerXWl5?VTO_>1HP1l(1&4=vm%?J6?nBuMB_i1Iz*U7)pdin~l}dwV_P>NDRJ&E?S(_7&sCYPaWk^WTljXxw$x zKC|FxAMsRF%IwzJ+%|@QLltQ;1!H_vjsg6aolZIqA6Y!y3zE7LFw*0q>2k)^igN0{ z+Jz1cF_)*Yblv+*Ud>AL^WLS7-0dklIaL4gZar=~%S(O_6?kw@D7=A1l_MxE`&C1Y zk?BPA=WG^1LPu!RzKzM2S?={_^@L^L^LO7l5$oN3`CPi6OVT9E=9suf@Dp<3i)t2>;rH|^8TLv!A7saQwDq5E@}_$A72R&u=6 zem|+0AVX~J`A~fGE%Tnw*4A&c`o~7oasqHQ=Qx-%ugdQUYYWm0Qm-4frWr^ETxDcusZRakn3Ft2LOWe=7IQLps&I~_iB*y*6; z+2+~w;fG`G3ZsT>{miepe9p3G=ULGgr#zDBa4bgZ4Ls)gH1&)v^)$NC)HU3R)^G!M z*}ki-GYM+HpU$Ed590vxGs`IqJ$ z(L4C2T(7kgeQ(A{ zQHqPFyUjKXS>$ny{RoI|0ZtnmkRV_sL( z`+3KtWZ{Z9ln68PPtPnIO{_~!Ix zzHCJD>DHUbH2Kf6S28q&)9|bM#S^~c(lHtjURzkaqA;DT^o>B6UM_!LXqhPSp(7?g z|KgL!H$9J6x;ZA*XlWn#l*)sTy{12Xx5viJfcIhrcNnU{6~g0SKO@@Z6_h(?ljK~g zL*^X0-}nN-9h@H+W53FMVJg;^?xW4v)#zN12+}2Xhu7`*KDuj+F=I7pfB)$*guTyNom9Y}SX&ua>>wFZMyZK3& z%GAar`u0B24UH$Q96Nbs;}LBK=fa;{NN^hGWsk71A?G#GbNnbp%(@@`*nvslzFk0J zf8U;go~mog^bYH;b!q2guX@;Vt}C1$ zDUPkkpjH(Z)o!P0aa6|cV>gg+^IGhpy&V@Aan)L{#=AD3xnogJ!Yf~PG89+stJ;xe zyyIa4baOzG!*=EP`i}1fK3MnTPA+mXvS+~B`@O(pTwEMZxnMkSHj<9+*4q$!!)S}6 zz@S*rm^)o;ff!2`N1?j93yoB?Q*F|XPX=$YCByE%D048kYh|~rp|m3nDNsA92j;C>)ba}Z zhnt6HS*P3vy{I3l=rZn7diJ8i)KxqJ8QR_45L$KnTFle?2E(Uh^i!{gvv0-`9YuU= zpQ-Hrpm~$yVk#qA`M!bv6hlJo?7XE=z$aLXkrF5eO?aHbYU8_%=nFKu*lfjg{Vu&y zlbh(JrqA`mzVh<3^E#V1xIWN-&+wS$k5@EE%m%E?-(Q{cEe~=7UahnB+D^3Osn>ZF zc!^G~?IiflE?))nj>}@|VU$Y)MuN5b44tYk>#)g&Kc!Jxm-Xt%q;-A#;IwrsbVP=? zAdcUx-RyR-ETc?Vi5Ts`HAV-cyp9H*IIQxpSwOqKV}8)hWXKaHIq~=!6C7Y4Kn(&Z{lNZXvQ`1Nm+BjL6(_0Tpgp#5Axm|wCz3c_C-vZozmlR`$IMq zSv#^?I(S_Nq?N+7q;INz`V^B_1RXcj*+_&OlYLIvdYnn^VR~W1i%^Z~Wa(7?tEH!8 z5_GPvl(xWLb(!}`9Bb!@ST5<`$-pljYHSw1JPhtCAWWeJ)-S##5*dvvRI`SdNa53f!iOTYivll7{_nc~`@u$=mh z)MBKxg0A;la@G;(`z|@?rS6{0GA{(5c#6>g=bYEv0kpH>q}s&$6DIjfLoLqEx|U3# zZSh08YIDm>wS5N)RZTf!h^;50J8$2TJEg3723_8$wJLEIAs*biIN!C_!8qt42tkK5 zSlwE`&CeXCG1XmMrsgie>NR{RFRSZjfyh-$BER~$S|@sEih->gTz@$2hElcS8JaT! z){LC5Zm{-XjQirtj`HX{yk%z^`kJC-TEI}#`0il_?3yDhHF=iL(qr%Nx zbe36^B1%j#_xFfZ-OjdHGNw8Z>CP;`MBOrI(1Y+s%}pIYy;Ia%0;lD3B2rL|Qp=##vXgl#!~H(!XC%fsc~*{5aZvKM#c z`6U%7s5YGtr&5-Hc z=M*FQ$5&%k2RgShEG$p(&@i;@Tz-$O}E_QP>$?t+99W6$80x~-JId`GcT^5t2yK8 zw?6ZNAD%YGKc{c)IJ9|WqYkk_w`(I~Fe00p+&_IfOO4InuRFACZF=8_sVk@Qlyj+1 zryJA0pvcCVUPE^iXb8Kc7`R$feU$c0I@#wazvvE1Ef7XmJmemfzY2PE?YMKW7u~Fq z#dyzchEh=>8^?+<6C34Ve`$J9$0vTb#}jPVOfD04xZN6+=$f_+Ebzj-yR5?6C=81? z!+s>^(kO-CVtq{#G*Tq{K3CO51?npxcM{qSdrsfhiMs96$|hoP`EJl9j$8PK$fFs} zi*9{kIeV*37)&fb`06EPG$xcC)PCHXRWV#4SIVN7F35~B<$9K1+Innw!f-Ul6? zN|udGn1m8nc#2q@wwjT6#>)x1$3u=XZM)?n~iX^r3AFK@BDb8JKl!vk7elZ`Moinby z8snlLTY9I)u&#(8mwZ;E?+KChu&Qxnj3Bm)Y4Y`;2HBgK(o*Q16VJKMQ}_`~X_M0J zA>?O=Gp!R}>36ZRh_STTMe|lGQt9_O$z)jPeL8gFokH-<6HjNAqs_0J&}MLUgv;>H z@$pWRD{1I8Gm@Rs*va*&UQm=#>cOlgzmuHYUYGoSyp!yjK%C#9S`9VEPh-jbQx96$ zeGW8IyBT9wr$S$3PP|=U9%XqQc;jTr6WV+Va!1L))PyvXwB+@O5A8e6rHxSxUJr9u zLv7xC#>@%VFEhK3`c}OuFtBoU3KkdA{J3u})N2gB(Zp+;U)*_S?6POV!|pQ;Z!ac3 zzjZ2rfnWK;K8aM}GFhL|7nL01mU=D;xf8eS%;uWfjO**q>9$A6P2KW#Vpa=HDLhFh z5DWiqmFJGd=f^22H6yTVs!Fj+ z+B}T)4c7`rReYcAV0r5Ig62S4T&m0PJ@d0F_M^^vNF!aj6LS2`5mvpIp_Kd8-QM>} zeJl?2u3#78a$@$(erMKvVu!s~?2?CkAG_Mb{Kh5w(>z{<6CP=ISL!SsJfA94V{z>& z+{9+da^{6iHbkzwUtI8c4A1=f$j zfwQ}Z85M%th8*D zBg}UQl*J3>PuxYD5cxJ;(W_6MM%+$LFkCutT50OmlWB*l64*sG zn7rJ&U)QA)ZK_y~EZb%eNfJUlECv?Ji_4;K4(v4} zUfC^(3$6%ZjgQx&ZFkwYYj#m1Zf8rz0orvDEiKLgoFV(V+=E+IHxK&Q6z}^aT6(ss zN1`j|SbVH}mXXBBLt=G#0a%3dloXrV{L37%-Uo>Xk1ItenceJ$w!u*u?alo|@x^B0 zjZe96LTzm%8GJtEFA3=+V4i^_%0ympoF!I08wm>0jFk|(oBl!b%4cxB_p=9PrMaoD zL)RG3M2g(nV`gmUINqFi+wMiiEeR$$P&|` zNM)DvQMMH!Im6D~p~z_XL9n-r?zB~r;b~}O#@jbRG13+=yX?($ql&( z|MECLzf)eW%HH1km;4n%Js1KH?xj9ZRIZ*|AU?7?MO_?Q5s%J!fP@1nm&a+23q@{(-xnJ4D!Dc8>4<1sc>*{uQ#(l1;X&%nPZ|H zjS8RRrsEY6)7{d^TDoCt1`l1+Ps|foE+oIK%A*flk+M1;N&oO=eSVs^_Yx0(i@0iU zeUiZ@Tr-DgP^0QE@$oGC(^8?~anCGxo=wB6e7Q)L=-0PvmMagNpP!{tFA`zA_wY&g z1+jw^`(^@#M-n|sTUuT+%bneuC$M+m$?JqW87sW*7q6Rf7824AyA|b_J1gzL(Kyg} z)$CZee`FUet}dxhoYwN11r03nW#`I1;U3Rb*VR1If8@a)N6yY+llz?BeF8TjV<(_Z zANr5FR1|;gduja^9oKj0sbX0Ll5hDF*YHR$|8m8wjF-!Xr$ASddgxp4S*N^w_&{Fm zh0|-0M|nsBN5$ zc;|@tgPup(G-&z^9F(f|UI{F%l;2pLe>;nklkSSyzh0JZf^m2&^1}3y&saeFO^52n z(iMVy7?0lw*q6#b_{N>HXKEjZPTXy3XU4`@ZaAtya~2rERYy|?`@FvG(rytC32n@Mq^OEre|FbAfBqyFAl&Q>z*83yNYG z3#{1ua98Mqz)DiiqU(pvk1y6DkW-JOPo7lK_ZGRE(inDJ%08W~)SJJMDzR57gX#%* zCdYa3J=n4n-w{CWC&4b7Y0hoHC8u}jPMYejL)l1zgtstF;oesIH#CE7BjU!KqlJPV zLFXY)iG^t`Sc z%^@Cp)Beh+sMd^r{S9cGr|f&kGl#tU%MF;&<>0UVC&&B3xg$@1Fg> zww5`Oqvw;N64-jKM!JGpvIjkxyEO8kTtUZL2e{Lb1uay}bPv0@SQ+_R?=_o?iZ81m zBbXB|`cE`1^RA}ya$20UxT+FO$t~wy!}=>)+6s0*G( zu4*3F8)qft(P2^k@+r+?JH?eU5zV)o8+l!K;G<{H-0J1ZSOl|G3EZrdQ@k7t>Aq6V zNq=2HI>A%lU@-|bbZ(nbH}fmQwb#clR+KM=TE}!xgR~{a#`JAZwhqERQx8ls)}?p zL(79HXvy5(6a^V_2Te9T5BB3lBgl-2b$fkJ@~2NzE6OLRPQKF!_AF+rJ8ufFzh&t?vu0Bj*nl!hEf&Zh!ofw;d0>V695)espS$CfCGG17!Q&!DW3TEMwt#TC2n3SNC+38b$RElXnp1a zQMPxv&m;96GNf$os-;{`vS;1g)W-fssi%zzKA+D+`nsoI3tCIfZfcQ@C?MPqhxfF) z_=~TPrVR2Uc8zuPo~X4#X2I5igakBW&Qa3Fzd#Q6#qQ~)Z;K^n=b5CQUZywX@<~eX z&Ixkr@>`VLjDD`!yfRCSkvTMVRLuMQ(`Wbfno7FzP3Ao;>Xp-IPK^kVxv0NweT|Qs$V|bM|_*kXYF-bdmBgOpU$=wZ{ zv^Q^wVbYI_-{|A6YrIyJTO$Dud_}1uUd_uNK5jYOn0cU(<@kJ|yS|K=Q~G#o3QHZq zkw+~$ujKfOe?JDoU>6i)pGdaPfqs@3bgN&qm8?|oje@mjragfr$Ti98h=Esnt(ekL ziYnyZsSFr~hUu8ba+sNa@hF0*(kCe!mLeTrajoT9Cr@O|*%_|vGf_@dyK5OgAGmgX zuU##{Kg^KG(ZbhO)aoB?`#74MYAEdWMeR40UBL*>I2CN+5MKdfWcAy8m7@`vWj89z z3vdxHXz3(g=kM7#K^1s2=JB!>U16~&F6GnV3GJ6?&?G0eVV9MRU`=#cJf%a)dVh4| z!O2^W(QP!^Ljy7|QZ6{MCF8^S4W8Y3X_Kh5f33h69-_dV*`B38^LAw2;f^S1#G`%P zG?d}dP7#S~;qlEEZ^~H@6(3U(7MD%ae*+G zY*+tuTuN+2Y%>;C$>rbW(G$i#by>IWovr;jru{(2Pv*?Hg z1>0iG7{&fW8)mUded?McdycnzuGeeFqH@}*Yw>-dH&&EXU)sgXe4I4WgU+HQcd4o| z-Z1Ld*pI7j4V0DLQ+Vex2|XW!mKvMfh8Tc zL-JwFW4$zs80k|+=e&80q&J|FrHPglH#DGZF_$Gp2MA|0A+~;HowEhz zJ%aGGLv>5CbPG%i%ko`M-^JZo4p63lG&JF2U1M>Y*Te72m+*e;(DvTbrq~G-9&eC} zkKY%zNUe=;)!uCswG5-pNtIsJ&C+l!nOh3cM(ajO0f&nGyM_i;w1xEF%uqHzTU;W4 zzVhU7+wya#r>(Bt4H8`x&ikjQ4R~nxO)LzDKuv>m>Mq+`;jXqBthy~QJ8DdhP< z$uL{4#WfejXQbAheMH(LQ*im(PCxckE?he`tJ7Ur9c zbwP)kiCzdk(en z*WYJ4MyQBt?dQHqx1>{Mp?ssfF0?!H&7R~VmIi*z#%yj+D+bd0Im}9oj+eb`ugtK$ zac@HQdAM$94)>*j2YumtwI5VwjS7O|Y<5;NY-T%zkr!|>l^0Fz7Cu~*ugm+O+L`WI z%q7Ybw(+0$X7XTCTxx?w_;}Rq&)gKFrSA7U;(dfpP51zQr!Gr}sdKN)(^G^Th9^^r zF$p@E0*?hMk2M7LUS&9ZWnYUVQq*;v#iF}3wfKCxmCW(8d1@_`f{uKxp4i*NW5Pm-9#Vp8OJ?kTcIQ|~-k2z=RgH$|vl z^elsCquy#6OX<HRKsNVhop%1p|NFS%-hd)XS`3{-Ei5MnYVjC|AJG^ zWL}qpHEGU!@YUJcB+04RH`2U?#pVPH2<}9S_+H_s3emUHD=b4x zdhK2xO0~3?+EcF=k+HBlVJ*Th^~$R-KGRTCD>W`h5&U?wRPUV{YIlR(i($3Gmy`qR zFTT;jgy;aE;g=NsMcqUk%VdMJ4}C^y88P%2&@~% z31{>5`i=h_yduqiOV)R()-e1=}=H=p87GR_?(6GFuB_7CE|FU<*I#Ik)Sv<%{)V0O?hKXD~ndpP=i<3Eq z>O7hj3Sq7^`KkQOw1;E$3i_umvMg8l>{x9PiWA>~6VJJZ5QobWAInH}w=_S}wZqb+ z8YfsbD>zZtNAu1LdyrR2xdf)BP9rr&o?jrJ`}D~alE^=Bi>x(p)8kNny`C011wZ8$ zvq(gKewcymzEbx`sPFG)`X`hk0QJ{RP1}PaJ^Sm2 z;>*iKr2k?en^U|D{3K0UZV%`CE1LefrS2~{e_hzLJ+SXDYx*Y`3&1g8I(h5nrR{-z ze{Iu0!3+Q}?4Ll9So8Hm{T;L70I0vNbNaVkeY*(Y`^%iRc142D@*n&P_1D!-|AzNX zy1s6U^pozpt)T!*|7B}`-D33Tc+B77o&65)%f%Sm6_S5$lH)tjmY+et-l+0#`~Akx z@9#GH=P9!TBVXU>|FYkI-m>w(?49eoy+8f=0bg$l`Cq{KzXO*75{e&o{}uf2D^dQO zLxO)j0}wSp;zIuO8Cw^a{P}a3zI%=l(6jtT%YS2TN4i;oO6?cS|5*@OzT>yicX->8 z!Ed|#{!X8N%HZ{1pnkpK=ij*c4f~&}^SwUu(EgJHe_i79=b)_Lu>t!X=vRsRU&NW` zJKTa_;%-ZlzwzSxt9|~-XY!r@r?hhk)vAi(_;nCO7aw#3MJ+3@FML*NzD*lA5KJMd z>kBSum|%g!A_Of|gw|T$cly@Lv(`Qv zM^4uN{Px-3{`UFq*}uidqPgsT`H~4I+xYN^&zp$2+~C1R_U_^3ZZzdYCm*n!iznrSsb}F?*ccv*KYHX4t zl5I^m(IRj|h&x}<gUF^%7V&7>J{FwlU8iccs|94E zw5s5fBI0O zt$9%qQP+Z)2o*fCX8|Yr!l|0=U;x=DEeK*F+kk)*edScmwj-#$M_1-3 zA`<$?L{{g|iH2XcRkLz`$VRz;=X>--XOm_>CbE)!PPFY6MO2{NhwQ>{Sh=(NS!WNP zrJZB*{Mo#HXZOOZiiyno@km+kJ|C$APSvc1AF|N~)cM|@oU4e)WFHe*k3A>)-Km51p!6WjbV|GQEY!`p|jy(S?>MYe$Fds@?Ywi&Qo_ z$K%no#&J&c$f=t3k3%-PLt93(eVv`USP_xtJ0`M{Z%#DkRLv^CA-nJ!Nq&ZJ>1?un z$3)ik&51^rsBtPVf7jll-Ah$ANwi}ktI*~|XPl~8p*CcrM7Z;;+qX;+kq17M%!w{JRkI>x$gcX`=IWb@h;+pVz91c@k-G)!$BBXlgd+lAxgbcfe=hE%%|JFX7)m@N9nkF#hj9B5h>! literal 0 HcmV?d00001 From b22909adc06ed9bdc6a5930db7293a5d842d1d12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Sun, 26 Apr 2020 17:36:36 +0200 Subject: [PATCH 04/29] CLean up workdir cache aoi --- .../util/CacheSupportingWorkdirProvider.java | 13 +--- .../util/CachingAllWorkdirProvider.java | 31 +++++---- .../repository/util/CreateWorkdirContext.java | 63 +++++++++++++++++++ .../util/NoneCachingWorkdirProvider.java | 10 +-- .../repository/util/SimpleWorkdirFactory.java | 38 +++++++---- .../scm/repository/util/WorkingCopy.java | 23 ++----- .../util/SimpleWorkdirFactoryTest.java | 11 ++-- 7 files changed, 125 insertions(+), 64 deletions(-) create mode 100644 scm-core/src/main/java/sonia/scm/repository/util/CreateWorkdirContext.java diff --git a/scm-core/src/main/java/sonia/scm/repository/util/CacheSupportingWorkdirProvider.java b/scm-core/src/main/java/sonia/scm/repository/util/CacheSupportingWorkdirProvider.java index e067d88f11..0a626b57d4 100644 --- a/scm-core/src/main/java/sonia/scm/repository/util/CacheSupportingWorkdirProvider.java +++ b/scm-core/src/main/java/sonia/scm/repository/util/CacheSupportingWorkdirProvider.java @@ -24,19 +24,10 @@ package sonia.scm.repository.util; -import sonia.scm.repository.Repository; - import java.io.File; -import java.io.IOException; public interface CacheSupportingWorkdirProvider { - SimpleWorkdirFactory.ParentAndClone getWorkdir( - Repository scmRepository, - String requestedBranch, - C context, - SimpleWorkdirFactory.WorkdirInitializer initializer, - SimpleWorkdirFactory.WorkdirReclaimer reclaimer - ) throws IOException; + SimpleWorkdirFactory.ParentAndClone getWorkdir(CreateWorkdirContext context) throws Exception; - boolean cache(Repository repository, File target) throws IOException; + void contextClosed(CreateWorkdirContext createWorkdirContext, File workdir) throws Exception; } diff --git a/scm-core/src/main/java/sonia/scm/repository/util/CachingAllWorkdirProvider.java b/scm-core/src/main/java/sonia/scm/repository/util/CachingAllWorkdirProvider.java index ebb9b7a7c6..75fcf24799 100644 --- a/scm-core/src/main/java/sonia/scm/repository/util/CachingAllWorkdirProvider.java +++ b/scm-core/src/main/java/sonia/scm/repository/util/CachingAllWorkdirProvider.java @@ -24,18 +24,17 @@ package sonia.scm.repository.util; -import sonia.scm.repository.Repository; import sonia.scm.util.IOUtil; import javax.inject.Inject; import java.io.File; import java.io.IOException; -import java.util.HashMap; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; public class CachingAllWorkdirProvider implements CacheSupportingWorkdirProvider { - private final Map workdirs = new HashMap<>(); + private final Map workdirs = new ConcurrentHashMap<>(); private final WorkdirProvider workdirProvider; @@ -45,18 +44,17 @@ public class CachingAllWorkdirProvider implements CacheSupportingWorkdirProvider } @Override - public SimpleWorkdirFactory.ParentAndClone getWorkdir(Repository scmRepository, String requestedBranch, C context, SimpleWorkdirFactory.WorkdirInitializer initializer, SimpleWorkdirFactory.WorkdirReclaimer reclaimer) throws IOException { - String id = scmRepository.getId(); - if (workdirs.containsKey(id)) { - File existingWorkdir = workdirs.get(id); + public SimpleWorkdirFactory.ParentAndClone getWorkdir(CreateWorkdirContext createWorkdirContext) throws IOException { + String id = createWorkdirContext.getScmRepository().getId(); + File existingWorkdir = workdirs.remove(id); + if (existingWorkdir != null) { try { - return reclaimer.reclaim(existingWorkdir); + return createWorkdirContext.getReclaimer().reclaim(existingWorkdir); } catch (SimpleWorkdirFactory.ReclaimFailedException e) { - workdirs.remove(id); - IOUtil.delete(existingWorkdir, true); + deleteWorkdir(existingWorkdir); } } - return createNewWorkdir(initializer, id); + return createNewWorkdir(createWorkdirContext.getInitializer(), id); } public SimpleWorkdirFactory.ParentAndClone createNewWorkdir(SimpleWorkdirFactory.WorkdirInitializer initializer, String id) throws IOException { @@ -66,7 +64,14 @@ public class CachingAllWorkdirProvider implements CacheSupportingWorkdirProvider } @Override - public boolean cache(Repository repository, File target) { - return true; + public void contextClosed(CreateWorkdirContext createWorkdirContext, File workdir) throws IOException { + String id = createWorkdirContext.getScmRepository().getId(); + if (workdirs.putIfAbsent(id, workdir) != null) { + deleteWorkdir(workdir); + } + } + + private void deleteWorkdir(File existingWorkdir) throws IOException { + IOUtil.delete(existingWorkdir, true); } } diff --git a/scm-core/src/main/java/sonia/scm/repository/util/CreateWorkdirContext.java b/scm-core/src/main/java/sonia/scm/repository/util/CreateWorkdirContext.java new file mode 100644 index 0000000000..26314d2f1e --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/repository/util/CreateWorkdirContext.java @@ -0,0 +1,63 @@ +/* + * 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.repository.util; + +import sonia.scm.repository.Repository; + +public class CreateWorkdirContext { + private final Repository scmRepository; + private final String requestedBranch; + private final C context; + private final SimpleWorkdirFactory.WorkdirInitializer initializer; + private final SimpleWorkdirFactory.WorkdirReclaimer reclaimer; + + public CreateWorkdirContext(Repository scmRepository, String requestedBranch, C context, SimpleWorkdirFactory.WorkdirInitializer initializer, SimpleWorkdirFactory.WorkdirReclaimer reclaimer) { + this.scmRepository = scmRepository; + this.requestedBranch = requestedBranch; + this.context = context; + this.initializer = initializer; + this.reclaimer = reclaimer; + } + + public Repository getScmRepository() { + return scmRepository; + } + + public String getRequestedBranch() { + return requestedBranch; + } + + public C getContext() { + return context; + } + + public SimpleWorkdirFactory.WorkdirInitializer getInitializer() { + return initializer; + } + + public SimpleWorkdirFactory.WorkdirReclaimer getReclaimer() { + return reclaimer; + } +} diff --git a/scm-core/src/main/java/sonia/scm/repository/util/NoneCachingWorkdirProvider.java b/scm-core/src/main/java/sonia/scm/repository/util/NoneCachingWorkdirProvider.java index b46c0dcdf3..3856bb9cad 100644 --- a/scm-core/src/main/java/sonia/scm/repository/util/NoneCachingWorkdirProvider.java +++ b/scm-core/src/main/java/sonia/scm/repository/util/NoneCachingWorkdirProvider.java @@ -24,7 +24,7 @@ package sonia.scm.repository.util; -import sonia.scm.repository.Repository; +import sonia.scm.util.IOUtil; import javax.inject.Inject; import java.io.File; @@ -40,12 +40,12 @@ public class NoneCachingWorkdirProvider implements CacheSupportingWorkdirProvide } @Override - public SimpleWorkdirFactory.ParentAndClone getWorkdir(Repository scmRepository, String requestedBranch, C context, SimpleWorkdirFactory.WorkdirInitializer initializer, SimpleWorkdirFactory.WorkdirReclaimer reclaimer) throws IOException { - return initializer.initialize(workdirProvider.createNewWorkdir()); + public SimpleWorkdirFactory.ParentAndClone getWorkdir(CreateWorkdirContext context) throws IOException { + return context.getInitializer().initialize(workdirProvider.createNewWorkdir()); } @Override - public boolean cache(Repository repository, File target) { - return false; + public void contextClosed(CreateWorkdirContext createWorkdirContext, File workdir) throws IOException { + IOUtil.delete(workdir, true); } } diff --git a/scm-core/src/main/java/sonia/scm/repository/util/SimpleWorkdirFactory.java b/scm-core/src/main/java/sonia/scm/repository/util/SimpleWorkdirFactory.java index 539dcac116..80f93a421e 100644 --- a/scm-core/src/main/java/sonia/scm/repository/util/SimpleWorkdirFactory.java +++ b/scm-core/src/main/java/sonia/scm/repository/util/SimpleWorkdirFactory.java @@ -34,7 +34,7 @@ import java.io.IOException; public abstract class SimpleWorkdirFactory implements WorkdirFactory { - private static final Logger logger = LoggerFactory.getLogger(SimpleWorkdirFactory.class); + private static final Logger LOG = LoggerFactory.getLogger(SimpleWorkdirFactory.class); private final CacheSupportingWorkdirProvider workdirProvider; @@ -45,26 +45,38 @@ public abstract class SimpleWorkdirFactory implements WorkdirFactory createWorkingCopy(C context, String initialBranch) { try { - ParentAndClone parentAndClone = workdirProvider.getWorkdir( + CreateWorkdirContext createWorkdirContext = new CreateWorkdirContext<>( getScmRepository(context), initialBranch, context, newFolder -> cloneRepository(context, newFolder, initialBranch), cachedFolder -> reclaimRepository(context, cachedFolder, initialBranch) ); - return new WorkingCopy(parentAndClone.getClone(), parentAndClone.getParent(), this::closeWorkdir, this::closeCentral, parentAndClone.getDirectory()) { - @Override - public void delete() throws IOException { - if (!workdirProvider.cache(getScmRepository(context), getDirectory())) { - super.delete(); - } - } - }; - } catch (IOException e) { + ParentAndClone parentAndClone = workdirProvider.getWorkdir(createWorkdirContext); + return new WorkingCopy<>(parentAndClone.getClone(), parentAndClone.getParent(), () -> this.close(createWorkdirContext, parentAndClone), parentAndClone.getDirectory()); + } catch (Exception e) { throw new InternalRepositoryException(getScmRepository(context), "could not clone repository in temporary directory", e); } } + private void close(CreateWorkdirContext createWorkdirContext, ParentAndClone parentAndClone) { + try { + closeRepository(parentAndClone.getParent()); + } catch (Exception e) { + LOG.warn("could not close central repository for {}", createWorkdirContext.getScmRepository(), e); + } + try { + closeWorkdir(parentAndClone.getClone()); + } catch (Exception e) { + LOG.warn("could not close clone for {} in directory {}", createWorkdirContext.getScmRepository(), parentAndClone.getDirectory(), e); + } + try { + workdirProvider.contextClosed(createWorkdirContext, parentAndClone.getDirectory()); + } catch (Exception e) { + LOG.warn("could not close context for {} with directory {}", createWorkdirContext.getScmRepository(), parentAndClone.getDirectory(), e); + } + } + @FunctionalInterface public interface WorkdirInitializer { ParentAndClone initialize(File target) throws IOException; @@ -92,7 +104,7 @@ public abstract class SimpleWorkdirFactory implements WorkdirFactory implements WorkdirFactory implements AutoCloseable { - - private static final Logger LOG = LoggerFactory.getLogger(WorkingCopy.class); +public final class WorkingCopy implements AutoCloseable { private final File directory; private final W workingRepository; private final R centralRepository; - private final Consumer cleanupWorkdir; - private final Consumer cleanupCentral; + private final Runnable close; - public WorkingCopy(W workingRepository, R centralRepository, Consumer cleanupWorkdir, Consumer cleanupCentral, File directory) { + public WorkingCopy(W workingRepository, R centralRepository, Runnable close, File directory) { this.directory = directory; this.workingRepository = workingRepository; this.centralRepository = centralRepository; - this.cleanupCentral = cleanupCentral; - this.cleanupWorkdir = cleanupWorkdir; + this.close = close; } public W getWorkingRepository() { @@ -64,13 +57,7 @@ public class WorkingCopy implements AutoCloseable { @Override public void close() { - try { - cleanupWorkdir.accept(workingRepository); - cleanupCentral.accept(centralRepository); - delete(); - } catch (IOException e) { - LOG.warn("could not delete temporary workdir '{}'", directory, e); - } + close.run(); } void delete() throws IOException { diff --git a/scm-core/src/test/java/sonia/scm/repository/util/SimpleWorkdirFactoryTest.java b/scm-core/src/test/java/sonia/scm/repository/util/SimpleWorkdirFactoryTest.java index ce634ee6d2..5299907270 100644 --- a/scm-core/src/test/java/sonia/scm/repository/util/SimpleWorkdirFactoryTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/util/SimpleWorkdirFactoryTest.java @@ -30,6 +30,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import sonia.scm.repository.Repository; +import sonia.scm.util.IOUtil; import java.io.Closeable; import java.io.File; @@ -60,14 +61,16 @@ public class SimpleWorkdirFactoryTest { WorkdirProvider workdirProvider = new WorkdirProvider(temporaryFolder.newFolder()); CacheSupportingWorkdirProvider configurableTestWorkdirProvider = new CacheSupportingWorkdirProvider() { @Override - public SimpleWorkdirFactory.ParentAndClone getWorkdir(Repository scmRepository, String requestedBranch, C context, SimpleWorkdirFactory.WorkdirInitializer initializer, SimpleWorkdirFactory.WorkdirReclaimer reclaimer) throws IOException { + public SimpleWorkdirFactory.ParentAndClone getWorkdir(CreateWorkdirContext context) throws IOException { workdir = workdirProvider.createNewWorkdir(); - return initializer.initialize(workdir); + return context.getInitializer().initialize(workdir); } @Override - public boolean cache(Repository repository, File target) { - return workdirIsCached; + public void contextClosed(CreateWorkdirContext createWorkdirContext, File workdir) throws Exception { + if (!workdirIsCached) { + IOUtil.delete(workdir); + } } }; simpleWorkdirFactory = new SimpleWorkdirFactory(configurableTestWorkdirProvider) { From f6a19b2ed78273384f2de63b6c1205e0311aff74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Sun, 26 Apr 2020 17:44:16 +0200 Subject: [PATCH 05/29] Stop time for workdir cache --- .../util/CachingAllWorkdirProvider.java | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/repository/util/CachingAllWorkdirProvider.java b/scm-core/src/main/java/sonia/scm/repository/util/CachingAllWorkdirProvider.java index 75fcf24799..e66f2fb7ae 100644 --- a/scm-core/src/main/java/sonia/scm/repository/util/CachingAllWorkdirProvider.java +++ b/scm-core/src/main/java/sonia/scm/repository/util/CachingAllWorkdirProvider.java @@ -24,6 +24,9 @@ package sonia.scm.repository.util; +import com.google.common.base.Stopwatch; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import sonia.scm.util.IOUtil; import javax.inject.Inject; @@ -34,6 +37,8 @@ import java.util.concurrent.ConcurrentHashMap; public class CachingAllWorkdirProvider implements CacheSupportingWorkdirProvider { + private static final Logger LOG = LoggerFactory.getLogger(CachingAllWorkdirProvider.class); + private final Map workdirs = new ConcurrentHashMap<>(); private final WorkdirProvider workdirProvider; @@ -48,19 +53,27 @@ public class CachingAllWorkdirProvider implements CacheSupportingWorkdirProvider String id = createWorkdirContext.getScmRepository().getId(); File existingWorkdir = workdirs.remove(id); if (existingWorkdir != null) { + Stopwatch stopwatch = Stopwatch.createStarted(); try { - return createWorkdirContext.getReclaimer().reclaim(existingWorkdir); + SimpleWorkdirFactory.ParentAndClone reclaimed = createWorkdirContext.getReclaimer().reclaim(existingWorkdir); + LOG.debug("reclaimed workdir for {} in path {} in {}", createWorkdirContext.getScmRepository().getNamespaceAndName(), existingWorkdir, stopwatch.stop()); + return reclaimed; } catch (SimpleWorkdirFactory.ReclaimFailedException e) { + LOG.debug("failed to relaim workdir for {} in path {} in {}", createWorkdirContext.getScmRepository().getNamespaceAndName(), existingWorkdir, stopwatch.stop(), e); deleteWorkdir(existingWorkdir); } } - return createNewWorkdir(createWorkdirContext.getInitializer(), id); + return createNewWorkdir(createWorkdirContext); } - public SimpleWorkdirFactory.ParentAndClone createNewWorkdir(SimpleWorkdirFactory.WorkdirInitializer initializer, String id) throws IOException { + private SimpleWorkdirFactory.ParentAndClone createNewWorkdir(CreateWorkdirContext createWorkdirContext) throws IOException { + String id = createWorkdirContext.getScmRepository().getId(); + Stopwatch stopwatch = Stopwatch.createStarted(); File newWorkdir = workdirProvider.createNewWorkdir(); workdirs.put(id, newWorkdir); - return initializer.initialize(newWorkdir); + SimpleWorkdirFactory.ParentAndClone parentAndClone = createWorkdirContext.getInitializer().initialize(newWorkdir); + LOG.debug("initialized new workdir for {} in path {} in {}", createWorkdirContext.getScmRepository().getNamespaceAndName(), newWorkdir, stopwatch.stop()); + return parentAndClone; } @Override From 0a87f4b87293313b826ad534fd535fe9d8652f13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Sun, 26 Apr 2020 18:11:08 +0200 Subject: [PATCH 06/29] Fix put to cache check putIfAbsent should return null, whenever there was no value for the key before it was put with the call. But however this does not seem to work with the concurrent hash map (liskov?) --- .../sonia/scm/repository/util/CachingAllWorkdirProvider.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scm-core/src/main/java/sonia/scm/repository/util/CachingAllWorkdirProvider.java b/scm-core/src/main/java/sonia/scm/repository/util/CachingAllWorkdirProvider.java index e66f2fb7ae..455ac14cdb 100644 --- a/scm-core/src/main/java/sonia/scm/repository/util/CachingAllWorkdirProvider.java +++ b/scm-core/src/main/java/sonia/scm/repository/util/CachingAllWorkdirProvider.java @@ -79,7 +79,8 @@ public class CachingAllWorkdirProvider implements CacheSupportingWorkdirProvider @Override public void contextClosed(CreateWorkdirContext createWorkdirContext, File workdir) throws IOException { String id = createWorkdirContext.getScmRepository().getId(); - if (workdirs.putIfAbsent(id, workdir) != null) { + File putResult = workdirs.putIfAbsent(id, workdir); + if (putResult != null && putResult != workdir) { deleteWorkdir(workdir); } } From 7ddb5284148133776f72eb9853ddc2d0d2fb0afa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Sun, 26 Apr 2020 21:34:40 +0200 Subject: [PATCH 07/29] Rethrow runtime exceptions to keep intention --- .../java/sonia/scm/repository/util/SimpleWorkdirFactory.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scm-core/src/main/java/sonia/scm/repository/util/SimpleWorkdirFactory.java b/scm-core/src/main/java/sonia/scm/repository/util/SimpleWorkdirFactory.java index 80f93a421e..f33369bf3b 100644 --- a/scm-core/src/main/java/sonia/scm/repository/util/SimpleWorkdirFactory.java +++ b/scm-core/src/main/java/sonia/scm/repository/util/SimpleWorkdirFactory.java @@ -54,6 +54,8 @@ public abstract class SimpleWorkdirFactory implements WorkdirFactory parentAndClone = workdirProvider.getWorkdir(createWorkdirContext); return new WorkingCopy<>(parentAndClone.getClone(), parentAndClone.getParent(), () -> this.close(createWorkdirContext, parentAndClone), parentAndClone.getDirectory()); + } catch (RuntimeException e) { + throw e; } catch (Exception e) { throw new InternalRepositoryException(getScmRepository(context), "could not clone repository in temporary directory", e); } From 5f96244b9b5d5036c8412aec98e7d51737ab8203 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Mon, 27 Apr 2020 08:03:30 +0200 Subject: [PATCH 08/29] Add shutdown --- .../util/CacheSupportingWorkdirProvider.java | 2 + .../util/CachingAllWorkdirProvider.java | 16 ++- .../util/NoneCachingWorkdirProvider.java | 4 + .../repository/util/SimpleWorkdirFactory.java | 16 ++- .../src/main/java/sonia/scm/util/IOUtil.java | 11 +- .../util/CachingAllWorkdirProviderTest.java | 124 ++++++++++++++++++ .../util/SimpleWorkdirFactoryTest.java | 5 + .../spi/SimpleHgWorkdirFactory.java | 1 + .../spi/SimpleSvnWorkDirFactory.java | 1 + 9 files changed, 173 insertions(+), 7 deletions(-) create mode 100644 scm-core/src/test/java/sonia/scm/repository/util/CachingAllWorkdirProviderTest.java diff --git a/scm-core/src/main/java/sonia/scm/repository/util/CacheSupportingWorkdirProvider.java b/scm-core/src/main/java/sonia/scm/repository/util/CacheSupportingWorkdirProvider.java index 0a626b57d4..c169932711 100644 --- a/scm-core/src/main/java/sonia/scm/repository/util/CacheSupportingWorkdirProvider.java +++ b/scm-core/src/main/java/sonia/scm/repository/util/CacheSupportingWorkdirProvider.java @@ -30,4 +30,6 @@ public interface CacheSupportingWorkdirProvider { SimpleWorkdirFactory.ParentAndClone getWorkdir(CreateWorkdirContext context) throws Exception; void contextClosed(CreateWorkdirContext createWorkdirContext, File workdir) throws Exception; + + void shutdown(); } diff --git a/scm-core/src/main/java/sonia/scm/repository/util/CachingAllWorkdirProvider.java b/scm-core/src/main/java/sonia/scm/repository/util/CachingAllWorkdirProvider.java index 455ac14cdb..ded3272c91 100644 --- a/scm-core/src/main/java/sonia/scm/repository/util/CachingAllWorkdirProvider.java +++ b/scm-core/src/main/java/sonia/scm/repository/util/CachingAllWorkdirProvider.java @@ -67,17 +67,15 @@ public class CachingAllWorkdirProvider implements CacheSupportingWorkdirProvider } private SimpleWorkdirFactory.ParentAndClone createNewWorkdir(CreateWorkdirContext createWorkdirContext) throws IOException { - String id = createWorkdirContext.getScmRepository().getId(); Stopwatch stopwatch = Stopwatch.createStarted(); File newWorkdir = workdirProvider.createNewWorkdir(); - workdirs.put(id, newWorkdir); SimpleWorkdirFactory.ParentAndClone parentAndClone = createWorkdirContext.getInitializer().initialize(newWorkdir); LOG.debug("initialized new workdir for {} in path {} in {}", createWorkdirContext.getScmRepository().getNamespaceAndName(), newWorkdir, stopwatch.stop()); return parentAndClone; } @Override - public void contextClosed(CreateWorkdirContext createWorkdirContext, File workdir) throws IOException { + public void contextClosed(CreateWorkdirContext createWorkdirContext, File workdir) { String id = createWorkdirContext.getScmRepository().getId(); File putResult = workdirs.putIfAbsent(id, workdir); if (putResult != null && putResult != workdir) { @@ -85,7 +83,15 @@ public class CachingAllWorkdirProvider implements CacheSupportingWorkdirProvider } } - private void deleteWorkdir(File existingWorkdir) throws IOException { - IOUtil.delete(existingWorkdir, true); + @Override + public void shutdown() { + workdirs.values().parallelStream().forEach(this::deleteWorkdir); + workdirs.clear(); + } + + private void deleteWorkdir(File existingWorkdir) { + if (existingWorkdir.exists()) { + IOUtil.deleteSilently(existingWorkdir); + } } } diff --git a/scm-core/src/main/java/sonia/scm/repository/util/NoneCachingWorkdirProvider.java b/scm-core/src/main/java/sonia/scm/repository/util/NoneCachingWorkdirProvider.java index 3856bb9cad..50feb3dbc8 100644 --- a/scm-core/src/main/java/sonia/scm/repository/util/NoneCachingWorkdirProvider.java +++ b/scm-core/src/main/java/sonia/scm/repository/util/NoneCachingWorkdirProvider.java @@ -48,4 +48,8 @@ public class NoneCachingWorkdirProvider implements CacheSupportingWorkdirProvide public void contextClosed(CreateWorkdirContext createWorkdirContext, File workdir) throws IOException { IOUtil.delete(workdir, true); } + + @Override + public void shutdown() { + } } diff --git a/scm-core/src/main/java/sonia/scm/repository/util/SimpleWorkdirFactory.java b/scm-core/src/main/java/sonia/scm/repository/util/SimpleWorkdirFactory.java index f33369bf3b..587a9306c6 100644 --- a/scm-core/src/main/java/sonia/scm/repository/util/SimpleWorkdirFactory.java +++ b/scm-core/src/main/java/sonia/scm/repository/util/SimpleWorkdirFactory.java @@ -26,13 +26,17 @@ package sonia.scm.repository.util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import sonia.scm.plugin.Extension; import sonia.scm.repository.InternalRepositoryException; import sonia.scm.repository.Repository; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; import java.io.File; import java.io.IOException; -public abstract class SimpleWorkdirFactory implements WorkdirFactory { +@Extension +public abstract class SimpleWorkdirFactory implements WorkdirFactory, ServletContextListener { private static final Logger LOG = LoggerFactory.getLogger(SimpleWorkdirFactory.class); @@ -79,6 +83,16 @@ public abstract class SimpleWorkdirFactory implements WorkdirFactory { ParentAndClone initialize(File target) throws IOException; diff --git a/scm-core/src/main/java/sonia/scm/util/IOUtil.java b/scm-core/src/main/java/sonia/scm/util/IOUtil.java index f1e63dd018..037f8e07ff 100644 --- a/scm-core/src/main/java/sonia/scm/util/IOUtil.java +++ b/scm-core/src/main/java/sonia/scm/util/IOUtil.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.util; //~--- non-JDK imports -------------------------------------------------------- @@ -358,6 +358,15 @@ public final class IOUtil delete(file, false); } + public static void deleteSilently(File file) + { + try { + delete(file, true); + } catch (IOException e) { + // silent delete throws no exception + } + } + /** * Method description * diff --git a/scm-core/src/test/java/sonia/scm/repository/util/CachingAllWorkdirProviderTest.java b/scm-core/src/test/java/sonia/scm/repository/util/CachingAllWorkdirProviderTest.java new file mode 100644 index 0000000000..1fcdbea3d2 --- /dev/null +++ b/scm-core/src/test/java/sonia/scm/repository/util/CachingAllWorkdirProviderTest.java @@ -0,0 +1,124 @@ +/* + * 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.repository.util; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junitpioneer.jupiter.TempDirectory; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import sonia.scm.repository.Repository; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith({MockitoExtension.class, TempDirectory.class}) +class CachingAllWorkdirProviderTest { + + private static final Repository REPOSITORY = new Repository("1", "git", "space", "X"); + + @Mock + WorkdirProvider workdirProvider; + @InjectMocks + CachingAllWorkdirProvider cachingAllWorkdirProvider; + + @Mock + CreateWorkdirContext createWorkdirContext; + @Mock + SimpleWorkdirFactory.WorkdirInitializer initializer; + @Mock + SimpleWorkdirFactory.WorkdirReclaimer reclaimer; + + @BeforeEach + void initContext() throws IOException, SimpleWorkdirFactory.ReclaimFailedException { + lenient().when(createWorkdirContext.getInitializer()).thenReturn(initializer); + lenient().when(createWorkdirContext.getReclaimer()).thenReturn(reclaimer); + + lenient().when(initializer.initialize(any())) + .thenAnswer(invocationOnMock -> new SimpleWorkdirFactory.ParentAndClone(null, null, invocationOnMock.getArgument(0, File.class))); + lenient().when(reclaimer.reclaim(any())) + .thenAnswer(invocationOnMock -> new SimpleWorkdirFactory.ParentAndClone(null, null, invocationOnMock.getArgument(0, File.class))); + } + + @Test + void shouldCreateNewWorkdirForTheFirstRequest(@TempDirectory.TempDir Path temp) throws IOException { + when(createWorkdirContext.getScmRepository()).thenReturn(REPOSITORY); + when(workdirProvider.createNewWorkdir()).thenReturn(temp.toFile()); + + SimpleWorkdirFactory.ParentAndClone workdir = cachingAllWorkdirProvider.getWorkdir(createWorkdirContext); + + verify(initializer).initialize(temp.toFile()); + } + + @Test + void shouldCreateWorkdirOnlyOnceForTheSameRepository(@TempDirectory.TempDir Path temp) throws IOException, SimpleWorkdirFactory.ReclaimFailedException { + when(createWorkdirContext.getScmRepository()).thenReturn(REPOSITORY); + when(workdirProvider.createNewWorkdir()).thenReturn(temp.toFile()); + + SimpleWorkdirFactory.ParentAndClone firstWorkdir = cachingAllWorkdirProvider.getWorkdir(createWorkdirContext); + cachingAllWorkdirProvider.contextClosed(createWorkdirContext, firstWorkdir.getDirectory()); + SimpleWorkdirFactory.ParentAndClone secondWorkdir = cachingAllWorkdirProvider.getWorkdir(createWorkdirContext); + + verify(initializer).initialize(temp.toFile()); + verify(reclaimer).reclaim(temp.toFile()); + assertThat(secondWorkdir.getDirectory()).isEqualTo(temp.toFile()); + } + + @Test + void shouldCacheOnlyOneWorkdirForRepository(@TempDirectory.TempDir Path temp) throws IOException, SimpleWorkdirFactory.ReclaimFailedException { + when(createWorkdirContext.getScmRepository()).thenReturn(REPOSITORY); + File firstDirectory = temp.resolve("first").toFile(); + firstDirectory.mkdirs(); + File secondDirectory = temp.resolve("second").toFile(); + secondDirectory.mkdirs(); + when(workdirProvider.createNewWorkdir()).thenReturn( + firstDirectory, + secondDirectory); + + SimpleWorkdirFactory.ParentAndClone firstWorkdir = cachingAllWorkdirProvider.getWorkdir(createWorkdirContext); + SimpleWorkdirFactory.ParentAndClone secondWorkdir = cachingAllWorkdirProvider.getWorkdir(createWorkdirContext); + cachingAllWorkdirProvider.contextClosed(createWorkdirContext, firstWorkdir.getDirectory()); + cachingAllWorkdirProvider.contextClosed(createWorkdirContext, secondWorkdir.getDirectory()); + + verify(reclaimer, never()).reclaim(any()); + verify(initializer).initialize(firstDirectory); + verify(initializer).initialize(secondDirectory); + assertThat(firstWorkdir.getDirectory()).isNotEqualTo(secondWorkdir.getDirectory()); + assertThat(firstWorkdir.getDirectory()).exists(); + assertThat(secondWorkdir.getDirectory()).doesNotExist(); + } +} diff --git a/scm-core/src/test/java/sonia/scm/repository/util/SimpleWorkdirFactoryTest.java b/scm-core/src/test/java/sonia/scm/repository/util/SimpleWorkdirFactoryTest.java index 5299907270..b8bf7a5366 100644 --- a/scm-core/src/test/java/sonia/scm/repository/util/SimpleWorkdirFactoryTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/util/SimpleWorkdirFactoryTest.java @@ -32,6 +32,7 @@ import org.junit.rules.TemporaryFolder; import sonia.scm.repository.Repository; import sonia.scm.util.IOUtil; +import javax.servlet.ServletContextEvent; import java.io.Closeable; import java.io.File; import java.io.IOException; @@ -72,6 +73,10 @@ public class SimpleWorkdirFactoryTest { IOUtil.delete(workdir); } } + + @Override + public void shutdown() { + } }; simpleWorkdirFactory = new SimpleWorkdirFactory(configurableTestWorkdirProvider) { @Override diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkdirFactory.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkdirFactory.java index 5663ab355e..85f4a7bd4f 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkdirFactory.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkdirFactory.java @@ -36,6 +36,7 @@ import sonia.scm.web.HgRepositoryEnvironmentBuilder; import javax.inject.Inject; import javax.inject.Provider; +import javax.servlet.ServletContextEvent; import java.io.File; import java.io.IOException; import java.util.Map; 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 3d88d79388..c05fe6baf1 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 @@ -40,6 +40,7 @@ import sonia.scm.repository.util.CacheSupportingWorkdirProvider; import sonia.scm.repository.util.SimpleWorkdirFactory; import javax.inject.Inject; +import javax.servlet.ServletContextEvent; import java.io.File; import java.io.IOException; From 8bd17a03d7da9a635e0c980198f92455f08d149b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Sun, 3 May 2020 15:41:03 +0200 Subject: [PATCH 09/29] Use better names The name 'workdir' is now only used for a concrete directory, where a clone can be created in. The new name 'working copy' is used for a concrete instance of such a directory, where a clone has been created in for a repository stored in SCM-Manager. Such a working copy can be cached and reused for further changes. --- ...er.java => CachingAllWorkingCopyPool.java} | 30 ++++----- ...r.java => NoneCachingWorkingCopyPool.java} | 8 +-- ...ory.java => SimpleWorkingCopyFactory.java} | 62 ++++++++++--------- .../scm/repository/util/WorkdirProvider.java | 14 ++--- ...irContext.java => WorkingCopyContext.java} | 12 ++-- ...irFactory.java => WorkingCopyFactory.java} | 6 +- ...kdirProvider.java => WorkingCopyPool.java} | 6 +- ...ava => CachingAllWorkingCopyPoolTest.java} | 54 ++++++++-------- ...java => SimpleWorkingCopyFactoryTest.java} | 29 +++++---- .../scm/repository/GitRepositoryHandler.java | 12 ++-- ...actory.java => GitWorkingCopyFactory.java} | 6 +- .../repository/spi/AbstractGitCommand.java | 6 +- .../scm/repository/spi/GitMergeCommand.java | 16 ++--- .../scm/repository/spi/GitModifyCommand.java | 10 +-- .../spi/GitRepositoryServiceProvider.java | 4 +- ....java => SimpleGitWorkingCopyFactory.java} | 18 +++--- .../java/sonia/scm/web/GitServletModule.java | 10 +-- .../repository/GitRepositoryHandlerTest.java | 8 +-- .../repository/spi/GitMergeCommandTest.java | 10 +-- .../spi/GitMergeCommand_Conflict_Test.java | 4 +- .../repository/spi/GitModifyCommandTest.java | 4 +- .../spi/GitModifyCommand_LFSTest.java | 4 +- ...ModifyCommand_withEmptyRepositoryTest.java | 4 +- ...a => SimpleGitWorkingCopyFactoryTest.java} | 26 ++++---- .../scm/repository/HgRepositoryHandler.java | 12 ++-- .../scm/repository/spi/HgBranchCommand.java | 12 ++-- .../scm/repository/spi/HgModifyCommand.java | 12 ++-- .../spi/HgRepositoryServiceProvider.java | 4 +- ...Factory.java => HgWorkingCopyFactory.java} | 6 +- ...y.java => SimpleHgWorkingCopyFactory.java} | 13 ++-- .../java/sonia/scm/web/HgServletModule.java | 8 +-- .../repository/spi/HgBranchCommandTest.java | 18 +++--- .../repository/spi/HgModifyCommandTest.java | 6 +- ...actory.java => SvnWorkingCopyFactory.java} | 6 +- ....java => SimpleSvnWorkingCopyFactory.java} | 17 +++-- .../scm/repository/spi/SvnModifyCommand.java | 10 +-- .../spi/SvnRepositoryServiceProvider.java | 10 +-- .../spi/SvnRepositoryServiceResolver.java | 12 ++-- .../java/sonia/scm/web/SvnServletModule.java | 8 +-- ...a => SimpleSvnWorkingCopyFactoryTest.java} | 12 ++-- .../repository/spi/SvnModifyCommandTest.java | 14 ++--- .../modules/ApplicationModuleProvider.java | 2 +- ...Module.java => WorkingCopyPoolModule.java} | 18 +++--- 43 files changed, 280 insertions(+), 283 deletions(-) rename scm-core/src/main/java/sonia/scm/repository/util/{CachingAllWorkdirProvider.java => CachingAllWorkingCopyPool.java} (64%) rename scm-core/src/main/java/sonia/scm/repository/util/{NoneCachingWorkdirProvider.java => NoneCachingWorkingCopyPool.java} (80%) rename scm-core/src/main/java/sonia/scm/repository/util/{SimpleWorkdirFactory.java => SimpleWorkingCopyFactory.java} (64%) rename scm-core/src/main/java/sonia/scm/repository/util/{CreateWorkdirContext.java => WorkingCopyContext.java} (75%) rename scm-core/src/main/java/sonia/scm/repository/util/{WorkdirFactory.java => WorkingCopyFactory.java} (90%) rename scm-core/src/main/java/sonia/scm/repository/util/{CacheSupportingWorkdirProvider.java => WorkingCopyPool.java} (81%) rename scm-core/src/test/java/sonia/scm/repository/util/{CachingAllWorkdirProviderTest.java => CachingAllWorkingCopyPoolTest.java} (55%) rename scm-core/src/test/java/sonia/scm/repository/util/{SimpleWorkdirFactoryTest.java => SimpleWorkingCopyFactoryTest.java} (81%) rename scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/{GitWorkdirFactory.java => GitWorkingCopyFactory.java} (89%) rename scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/{SimpleGitWorkdirFactory.java => SimpleGitWorkingCopyFactory.java} (89%) rename scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/{SimpleGitWorkdirFactoryTest.java => SimpleGitWorkingCopyFactoryTest.java} (83%) rename scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/{HgWorkdirFactory.java => HgWorkingCopyFactory.java} (89%) rename scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/{SimpleHgWorkdirFactory.java => SimpleHgWorkingCopyFactory.java} (87%) rename scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/{SvnWorkDirFactory.java => SvnWorkingCopyFactory.java} (89%) rename scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/{SimpleSvnWorkDirFactory.java => SimpleSvnWorkingCopyFactory.java} (85%) rename scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/{SimpleSvnWorkDirFactoryTest.java => SimpleSvnWorkingCopyFactoryTest.java} (84%) rename scm-webapp/src/main/java/sonia/scm/lifecycle/modules/{WorkdirModule.java => WorkingCopyPoolModule.java} (63%) diff --git a/scm-core/src/main/java/sonia/scm/repository/util/CachingAllWorkdirProvider.java b/scm-core/src/main/java/sonia/scm/repository/util/CachingAllWorkingCopyPool.java similarity index 64% rename from scm-core/src/main/java/sonia/scm/repository/util/CachingAllWorkdirProvider.java rename to scm-core/src/main/java/sonia/scm/repository/util/CachingAllWorkingCopyPool.java index ded3272c91..76e3c0b9b0 100644 --- a/scm-core/src/main/java/sonia/scm/repository/util/CachingAllWorkdirProvider.java +++ b/scm-core/src/main/java/sonia/scm/repository/util/CachingAllWorkingCopyPool.java @@ -35,48 +35,48 @@ import java.io.IOException; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -public class CachingAllWorkdirProvider implements CacheSupportingWorkdirProvider { +public class CachingAllWorkingCopyPool implements WorkingCopyPool { - private static final Logger LOG = LoggerFactory.getLogger(CachingAllWorkdirProvider.class); + private static final Logger LOG = LoggerFactory.getLogger(CachingAllWorkingCopyPool.class); private final Map workdirs = new ConcurrentHashMap<>(); private final WorkdirProvider workdirProvider; @Inject - public CachingAllWorkdirProvider(WorkdirProvider workdirProvider) { + public CachingAllWorkingCopyPool(WorkdirProvider workdirProvider) { this.workdirProvider = workdirProvider; } @Override - public SimpleWorkdirFactory.ParentAndClone getWorkdir(CreateWorkdirContext createWorkdirContext) throws IOException { - String id = createWorkdirContext.getScmRepository().getId(); + public SimpleWorkingCopyFactory.ParentAndClone getWorkingCopy(WorkingCopyContext workingCopyContext) throws IOException { + String id = workingCopyContext.getScmRepository().getId(); File existingWorkdir = workdirs.remove(id); if (existingWorkdir != null) { Stopwatch stopwatch = Stopwatch.createStarted(); try { - SimpleWorkdirFactory.ParentAndClone reclaimed = createWorkdirContext.getReclaimer().reclaim(existingWorkdir); - LOG.debug("reclaimed workdir for {} in path {} in {}", createWorkdirContext.getScmRepository().getNamespaceAndName(), existingWorkdir, stopwatch.stop()); + SimpleWorkingCopyFactory.ParentAndClone reclaimed = workingCopyContext.getReclaimer().reclaim(existingWorkdir); + LOG.debug("reclaimed workdir for {} in path {} in {}", workingCopyContext.getScmRepository().getNamespaceAndName(), existingWorkdir, stopwatch.stop()); return reclaimed; - } catch (SimpleWorkdirFactory.ReclaimFailedException e) { - LOG.debug("failed to relaim workdir for {} in path {} in {}", createWorkdirContext.getScmRepository().getNamespaceAndName(), existingWorkdir, stopwatch.stop(), e); + } catch (SimpleWorkingCopyFactory.ReclaimFailedException e) { + LOG.debug("failed to reclaim workdir for {} in path {} in {}", workingCopyContext.getScmRepository().getNamespaceAndName(), existingWorkdir, stopwatch.stop(), e); deleteWorkdir(existingWorkdir); } } - return createNewWorkdir(createWorkdirContext); + return createNewWorkdir(workingCopyContext); } - private SimpleWorkdirFactory.ParentAndClone createNewWorkdir(CreateWorkdirContext createWorkdirContext) throws IOException { + private SimpleWorkingCopyFactory.ParentAndClone createNewWorkdir(WorkingCopyContext workingCopyContext) throws IOException { Stopwatch stopwatch = Stopwatch.createStarted(); File newWorkdir = workdirProvider.createNewWorkdir(); - SimpleWorkdirFactory.ParentAndClone parentAndClone = createWorkdirContext.getInitializer().initialize(newWorkdir); - LOG.debug("initialized new workdir for {} in path {} in {}", createWorkdirContext.getScmRepository().getNamespaceAndName(), newWorkdir, stopwatch.stop()); + SimpleWorkingCopyFactory.ParentAndClone parentAndClone = workingCopyContext.getInitializer().initialize(newWorkdir); + LOG.debug("initialized new workdir for {} in path {} in {}", workingCopyContext.getScmRepository().getNamespaceAndName(), newWorkdir, stopwatch.stop()); return parentAndClone; } @Override - public void contextClosed(CreateWorkdirContext createWorkdirContext, File workdir) { - String id = createWorkdirContext.getScmRepository().getId(); + public void contextClosed(WorkingCopyContext workingCopyContext, File workdir) { + String id = workingCopyContext.getScmRepository().getId(); File putResult = workdirs.putIfAbsent(id, workdir); if (putResult != null && putResult != workdir) { deleteWorkdir(workdir); diff --git a/scm-core/src/main/java/sonia/scm/repository/util/NoneCachingWorkdirProvider.java b/scm-core/src/main/java/sonia/scm/repository/util/NoneCachingWorkingCopyPool.java similarity index 80% rename from scm-core/src/main/java/sonia/scm/repository/util/NoneCachingWorkdirProvider.java rename to scm-core/src/main/java/sonia/scm/repository/util/NoneCachingWorkingCopyPool.java index 50feb3dbc8..a00ee5d3eb 100644 --- a/scm-core/src/main/java/sonia/scm/repository/util/NoneCachingWorkdirProvider.java +++ b/scm-core/src/main/java/sonia/scm/repository/util/NoneCachingWorkingCopyPool.java @@ -30,22 +30,22 @@ import javax.inject.Inject; import java.io.File; import java.io.IOException; -public class NoneCachingWorkdirProvider implements CacheSupportingWorkdirProvider { +public class NoneCachingWorkingCopyPool implements WorkingCopyPool { private final WorkdirProvider workdirProvider; @Inject - public NoneCachingWorkdirProvider(WorkdirProvider workdirProvider) { + public NoneCachingWorkingCopyPool(WorkdirProvider workdirProvider) { this.workdirProvider = workdirProvider; } @Override - public SimpleWorkdirFactory.ParentAndClone getWorkdir(CreateWorkdirContext context) throws IOException { + public SimpleWorkingCopyFactory.ParentAndClone getWorkingCopy(WorkingCopyContext context) throws IOException { return context.getInitializer().initialize(workdirProvider.createNewWorkdir()); } @Override - public void contextClosed(CreateWorkdirContext createWorkdirContext, File workdir) throws IOException { + public void contextClosed(WorkingCopyContext workingCopyContext, File workdir) throws IOException { IOUtil.delete(workdir, true); } diff --git a/scm-core/src/main/java/sonia/scm/repository/util/SimpleWorkdirFactory.java b/scm-core/src/main/java/sonia/scm/repository/util/SimpleWorkingCopyFactory.java similarity index 64% rename from scm-core/src/main/java/sonia/scm/repository/util/SimpleWorkdirFactory.java rename to scm-core/src/main/java/sonia/scm/repository/util/SimpleWorkingCopyFactory.java index 587a9306c6..963300d84a 100644 --- a/scm-core/src/main/java/sonia/scm/repository/util/SimpleWorkdirFactory.java +++ b/scm-core/src/main/java/sonia/scm/repository/util/SimpleWorkingCopyFactory.java @@ -36,56 +36,60 @@ import java.io.File; import java.io.IOException; @Extension -public abstract class SimpleWorkdirFactory implements WorkdirFactory, ServletContextListener { +public abstract class SimpleWorkingCopyFactory implements WorkingCopyFactory, ServletContextListener { - private static final Logger LOG = LoggerFactory.getLogger(SimpleWorkdirFactory.class); + private static final Logger LOG = LoggerFactory.getLogger(SimpleWorkingCopyFactory.class); - private final CacheSupportingWorkdirProvider workdirProvider; + private final WorkingCopyPool workingCopyPool; - public SimpleWorkdirFactory(CacheSupportingWorkdirProvider workdirProvider) { - this.workdirProvider = workdirProvider; + public SimpleWorkingCopyFactory(WorkingCopyPool workingCopyPool) { + this.workingCopyPool = workingCopyPool; } @Override - public WorkingCopy createWorkingCopy(C context, String initialBranch) { + public WorkingCopy createWorkingCopy(C repositoryContext, String initialBranch) { try { - CreateWorkdirContext createWorkdirContext = new CreateWorkdirContext<>( - getScmRepository(context), - initialBranch, - context, - newFolder -> cloneRepository(context, newFolder, initialBranch), - cachedFolder -> reclaimRepository(context, cachedFolder, initialBranch) - ); - ParentAndClone parentAndClone = workdirProvider.getWorkdir(createWorkdirContext); - return new WorkingCopy<>(parentAndClone.getClone(), parentAndClone.getParent(), () -> this.close(createWorkdirContext, parentAndClone), parentAndClone.getDirectory()); + WorkingCopyContext workingCopyContext = createWorkingCopyContext(repositoryContext, initialBranch); + ParentAndClone parentAndClone = workingCopyPool.getWorkingCopy(workingCopyContext); + return new WorkingCopy<>(parentAndClone.getClone(), parentAndClone.getParent(), () -> this.close(workingCopyContext, parentAndClone), parentAndClone.getDirectory()); } catch (RuntimeException e) { throw e; } catch (Exception e) { - throw new InternalRepositoryException(getScmRepository(context), "could not clone repository in temporary directory", e); + throw new InternalRepositoryException(getScmRepository(repositoryContext), "could not clone repository in temporary directory", e); } } - private void close(CreateWorkdirContext createWorkdirContext, ParentAndClone parentAndClone) { + public WorkingCopyContext createWorkingCopyContext(C repositoryContext, String initialBranch) { + return new WorkingCopyContext<>( + getScmRepository(repositoryContext), + initialBranch, + repositoryContext, + newFolder -> cloneRepository(repositoryContext, newFolder, initialBranch), + cachedFolder -> reclaimRepository(repositoryContext, cachedFolder, initialBranch) + ); + } + + private void close(WorkingCopyContext workingCopyContext, ParentAndClone parentAndClone) { try { closeRepository(parentAndClone.getParent()); } catch (Exception e) { - LOG.warn("could not close central repository for {}", createWorkdirContext.getScmRepository(), e); + LOG.warn("could not close central repository for {}", workingCopyContext.getScmRepository(), e); } try { - closeWorkdir(parentAndClone.getClone()); + closeWorkingCopy(parentAndClone.getClone()); } catch (Exception e) { - LOG.warn("could not close clone for {} in directory {}", createWorkdirContext.getScmRepository(), parentAndClone.getDirectory(), e); + LOG.warn("could not close clone for {} in directory {}", workingCopyContext.getScmRepository(), parentAndClone.getDirectory(), e); } try { - workdirProvider.contextClosed(createWorkdirContext, parentAndClone.getDirectory()); + workingCopyPool.contextClosed(workingCopyContext, parentAndClone.getDirectory()); } catch (Exception e) { - LOG.warn("could not close context for {} with directory {}", createWorkdirContext.getScmRepository(), parentAndClone.getDirectory(), e); + LOG.warn("could not close context for {} with directory {}", workingCopyContext.getScmRepository(), parentAndClone.getDirectory(), e); } } @Override public void contextDestroyed(ServletContextEvent sce) { - workdirProvider.shutdown(); + workingCopyPool.shutdown(); } @Override @@ -94,12 +98,12 @@ public abstract class SimpleWorkdirFactory implements WorkdirFactory { + public interface WorkingCopyInitializer { ParentAndClone initialize(File target) throws IOException; } @FunctionalInterface - public interface WorkdirReclaimer { + public interface WorkingCopyReclaimer { ParentAndClone reclaim(File target) throws IOException, ReclaimFailedException; } @@ -109,8 +113,8 @@ public abstract class SimpleWorkdirFactory implements WorkdirFactory cloneRepository(C context, File target, String initialBranch) throws IOException; @@ -124,9 +128,9 @@ public abstract class SimpleWorkdirFactory implements WorkdirFactory { +public class WorkingCopyContext { private final Repository scmRepository; private final String requestedBranch; private final C context; - private final SimpleWorkdirFactory.WorkdirInitializer initializer; - private final SimpleWorkdirFactory.WorkdirReclaimer reclaimer; + private final SimpleWorkingCopyFactory.WorkingCopyInitializer initializer; + private final SimpleWorkingCopyFactory.WorkingCopyReclaimer reclaimer; - public CreateWorkdirContext(Repository scmRepository, String requestedBranch, C context, SimpleWorkdirFactory.WorkdirInitializer initializer, SimpleWorkdirFactory.WorkdirReclaimer reclaimer) { + public WorkingCopyContext(Repository scmRepository, String requestedBranch, C context, SimpleWorkingCopyFactory.WorkingCopyInitializer initializer, SimpleWorkingCopyFactory.WorkingCopyReclaimer reclaimer) { this.scmRepository = scmRepository; this.requestedBranch = requestedBranch; this.context = context; @@ -53,11 +53,11 @@ public class CreateWorkdirContext { return context; } - public SimpleWorkdirFactory.WorkdirInitializer getInitializer() { + public SimpleWorkingCopyFactory.WorkingCopyInitializer getInitializer() { return initializer; } - public SimpleWorkdirFactory.WorkdirReclaimer getReclaimer() { + public SimpleWorkingCopyFactory.WorkingCopyReclaimer getReclaimer() { return reclaimer; } } diff --git a/scm-core/src/main/java/sonia/scm/repository/util/WorkdirFactory.java b/scm-core/src/main/java/sonia/scm/repository/util/WorkingCopyFactory.java similarity index 90% rename from scm-core/src/main/java/sonia/scm/repository/util/WorkdirFactory.java rename to scm-core/src/main/java/sonia/scm/repository/util/WorkingCopyFactory.java index e3c72bc3ae..bc48edfceb 100644 --- a/scm-core/src/main/java/sonia/scm/repository/util/WorkdirFactory.java +++ b/scm-core/src/main/java/sonia/scm/repository/util/WorkingCopyFactory.java @@ -21,9 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.repository.util; -public interface WorkdirFactory { - WorkingCopy createWorkingCopy(C context, String initialBranch); +public interface WorkingCopyFactory { + WorkingCopy createWorkingCopy(C repositoryContext, String initialBranch); } diff --git a/scm-core/src/main/java/sonia/scm/repository/util/CacheSupportingWorkdirProvider.java b/scm-core/src/main/java/sonia/scm/repository/util/WorkingCopyPool.java similarity index 81% rename from scm-core/src/main/java/sonia/scm/repository/util/CacheSupportingWorkdirProvider.java rename to scm-core/src/main/java/sonia/scm/repository/util/WorkingCopyPool.java index c169932711..92bc081bb4 100644 --- a/scm-core/src/main/java/sonia/scm/repository/util/CacheSupportingWorkdirProvider.java +++ b/scm-core/src/main/java/sonia/scm/repository/util/WorkingCopyPool.java @@ -26,10 +26,10 @@ package sonia.scm.repository.util; import java.io.File; -public interface CacheSupportingWorkdirProvider { - SimpleWorkdirFactory.ParentAndClone getWorkdir(CreateWorkdirContext context) throws Exception; +public interface WorkingCopyPool { + SimpleWorkingCopyFactory.ParentAndClone getWorkingCopy(WorkingCopyContext context) throws Exception; - void contextClosed(CreateWorkdirContext createWorkdirContext, File workdir) throws Exception; + void contextClosed(WorkingCopyContext workingCopyContext, File workdir) throws Exception; void shutdown(); } diff --git a/scm-core/src/test/java/sonia/scm/repository/util/CachingAllWorkdirProviderTest.java b/scm-core/src/test/java/sonia/scm/repository/util/CachingAllWorkingCopyPoolTest.java similarity index 55% rename from scm-core/src/test/java/sonia/scm/repository/util/CachingAllWorkdirProviderTest.java rename to scm-core/src/test/java/sonia/scm/repository/util/CachingAllWorkingCopyPoolTest.java index 1fcdbea3d2..b5e011964c 100644 --- a/scm-core/src/test/java/sonia/scm/repository/util/CachingAllWorkdirProviderTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/util/CachingAllWorkingCopyPoolTest.java @@ -24,11 +24,10 @@ package sonia.scm.repository.util; -import org.assertj.core.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.junitpioneer.jupiter.TempDirectory; +import org.junit.jupiter.api.io.TempDir; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; @@ -42,56 +41,55 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -@ExtendWith({MockitoExtension.class, TempDirectory.class}) -class CachingAllWorkdirProviderTest { +@ExtendWith({MockitoExtension.class}) +class CachingAllWorkingCopyPoolTest { private static final Repository REPOSITORY = new Repository("1", "git", "space", "X"); @Mock WorkdirProvider workdirProvider; @InjectMocks - CachingAllWorkdirProvider cachingAllWorkdirProvider; + CachingAllWorkingCopyPool cachingAllWorkingCopyPool; @Mock - CreateWorkdirContext createWorkdirContext; + WorkingCopyContext workingCopyContext; @Mock - SimpleWorkdirFactory.WorkdirInitializer initializer; + SimpleWorkingCopyFactory.WorkingCopyInitializer initializer; @Mock - SimpleWorkdirFactory.WorkdirReclaimer reclaimer; + SimpleWorkingCopyFactory.WorkingCopyReclaimer reclaimer; @BeforeEach - void initContext() throws IOException, SimpleWorkdirFactory.ReclaimFailedException { - lenient().when(createWorkdirContext.getInitializer()).thenReturn(initializer); - lenient().when(createWorkdirContext.getReclaimer()).thenReturn(reclaimer); + void initContext() throws IOException, SimpleWorkingCopyFactory.ReclaimFailedException { + lenient().when(workingCopyContext.getInitializer()).thenReturn(initializer); + lenient().when(workingCopyContext.getReclaimer()).thenReturn(reclaimer); lenient().when(initializer.initialize(any())) - .thenAnswer(invocationOnMock -> new SimpleWorkdirFactory.ParentAndClone(null, null, invocationOnMock.getArgument(0, File.class))); + .thenAnswer(invocationOnMock -> new SimpleWorkingCopyFactory.ParentAndClone<>(null, null, invocationOnMock.getArgument(0, File.class))); lenient().when(reclaimer.reclaim(any())) - .thenAnswer(invocationOnMock -> new SimpleWorkdirFactory.ParentAndClone(null, null, invocationOnMock.getArgument(0, File.class))); + .thenAnswer(invocationOnMock -> new SimpleWorkingCopyFactory.ParentAndClone<>(null, null, invocationOnMock.getArgument(0, File.class))); } @Test - void shouldCreateNewWorkdirForTheFirstRequest(@TempDirectory.TempDir Path temp) throws IOException { - when(createWorkdirContext.getScmRepository()).thenReturn(REPOSITORY); + void shouldCreateNewWorkdirForTheFirstRequest(@TempDir Path temp) throws IOException { + when(workingCopyContext.getScmRepository()).thenReturn(REPOSITORY); when(workdirProvider.createNewWorkdir()).thenReturn(temp.toFile()); - SimpleWorkdirFactory.ParentAndClone workdir = cachingAllWorkdirProvider.getWorkdir(createWorkdirContext); + SimpleWorkingCopyFactory.ParentAndClone workdir = cachingAllWorkingCopyPool.getWorkingCopy(workingCopyContext); verify(initializer).initialize(temp.toFile()); } @Test - void shouldCreateWorkdirOnlyOnceForTheSameRepository(@TempDirectory.TempDir Path temp) throws IOException, SimpleWorkdirFactory.ReclaimFailedException { - when(createWorkdirContext.getScmRepository()).thenReturn(REPOSITORY); + void shouldCreateWorkdirOnlyOnceForTheSameRepository(@TempDir Path temp) throws IOException, SimpleWorkingCopyFactory.ReclaimFailedException { + when(workingCopyContext.getScmRepository()).thenReturn(REPOSITORY); when(workdirProvider.createNewWorkdir()).thenReturn(temp.toFile()); - SimpleWorkdirFactory.ParentAndClone firstWorkdir = cachingAllWorkdirProvider.getWorkdir(createWorkdirContext); - cachingAllWorkdirProvider.contextClosed(createWorkdirContext, firstWorkdir.getDirectory()); - SimpleWorkdirFactory.ParentAndClone secondWorkdir = cachingAllWorkdirProvider.getWorkdir(createWorkdirContext); + SimpleWorkingCopyFactory.ParentAndClone firstWorkdir = cachingAllWorkingCopyPool.getWorkingCopy(workingCopyContext); + cachingAllWorkingCopyPool.contextClosed(workingCopyContext, firstWorkdir.getDirectory()); + SimpleWorkingCopyFactory.ParentAndClone secondWorkdir = cachingAllWorkingCopyPool.getWorkingCopy(workingCopyContext); verify(initializer).initialize(temp.toFile()); verify(reclaimer).reclaim(temp.toFile()); @@ -99,8 +97,8 @@ class CachingAllWorkdirProviderTest { } @Test - void shouldCacheOnlyOneWorkdirForRepository(@TempDirectory.TempDir Path temp) throws IOException, SimpleWorkdirFactory.ReclaimFailedException { - when(createWorkdirContext.getScmRepository()).thenReturn(REPOSITORY); + void shouldCacheOnlyOneWorkdirForRepository(@TempDir Path temp) throws IOException, SimpleWorkingCopyFactory.ReclaimFailedException { + when(workingCopyContext.getScmRepository()).thenReturn(REPOSITORY); File firstDirectory = temp.resolve("first").toFile(); firstDirectory.mkdirs(); File secondDirectory = temp.resolve("second").toFile(); @@ -109,10 +107,10 @@ class CachingAllWorkdirProviderTest { firstDirectory, secondDirectory); - SimpleWorkdirFactory.ParentAndClone firstWorkdir = cachingAllWorkdirProvider.getWorkdir(createWorkdirContext); - SimpleWorkdirFactory.ParentAndClone secondWorkdir = cachingAllWorkdirProvider.getWorkdir(createWorkdirContext); - cachingAllWorkdirProvider.contextClosed(createWorkdirContext, firstWorkdir.getDirectory()); - cachingAllWorkdirProvider.contextClosed(createWorkdirContext, secondWorkdir.getDirectory()); + SimpleWorkingCopyFactory.ParentAndClone firstWorkdir = cachingAllWorkingCopyPool.getWorkingCopy(workingCopyContext); + SimpleWorkingCopyFactory.ParentAndClone secondWorkdir = cachingAllWorkingCopyPool.getWorkingCopy(workingCopyContext); + cachingAllWorkingCopyPool.contextClosed(workingCopyContext, firstWorkdir.getDirectory()); + cachingAllWorkingCopyPool.contextClosed(workingCopyContext, secondWorkdir.getDirectory()); verify(reclaimer, never()).reclaim(any()); verify(initializer).initialize(firstDirectory); diff --git a/scm-core/src/test/java/sonia/scm/repository/util/SimpleWorkdirFactoryTest.java b/scm-core/src/test/java/sonia/scm/repository/util/SimpleWorkingCopyFactoryTest.java similarity index 81% rename from scm-core/src/test/java/sonia/scm/repository/util/SimpleWorkdirFactoryTest.java rename to scm-core/src/test/java/sonia/scm/repository/util/SimpleWorkingCopyFactoryTest.java index b8bf7a5366..87e80d65bd 100644 --- a/scm-core/src/test/java/sonia/scm/repository/util/SimpleWorkdirFactoryTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/util/SimpleWorkingCopyFactoryTest.java @@ -32,7 +32,6 @@ import org.junit.rules.TemporaryFolder; import sonia.scm.repository.Repository; import sonia.scm.util.IOUtil; -import javax.servlet.ServletContextEvent; import java.io.Closeable; import java.io.File; import java.io.IOException; @@ -41,7 +40,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; -public class SimpleWorkdirFactoryTest { +public class SimpleWorkingCopyFactoryTest { private static final Repository REPOSITORY = new Repository("1", "git", "space", "X"); @@ -50,7 +49,7 @@ public class SimpleWorkdirFactoryTest { @Rule public TemporaryFolder temporaryFolder = new TemporaryFolder(); - private SimpleWorkdirFactory simpleWorkdirFactory; + private SimpleWorkingCopyFactory simpleWorkingCopyFactory; private String initialBranchForLastCloneCall; @@ -60,15 +59,15 @@ public class SimpleWorkdirFactoryTest { @Before public void initFactory() throws IOException { WorkdirProvider workdirProvider = new WorkdirProvider(temporaryFolder.newFolder()); - CacheSupportingWorkdirProvider configurableTestWorkdirProvider = new CacheSupportingWorkdirProvider() { + WorkingCopyPool configurableTestWorkingCopyPool = new WorkingCopyPool() { @Override - public SimpleWorkdirFactory.ParentAndClone getWorkdir(CreateWorkdirContext context) throws IOException { + public SimpleWorkingCopyFactory.ParentAndClone getWorkingCopy(WorkingCopyContext context) throws IOException { workdir = workdirProvider.createNewWorkdir(); return context.getInitializer().initialize(workdir); } @Override - public void contextClosed(CreateWorkdirContext createWorkdirContext, File workdir) throws Exception { + public void contextClosed(WorkingCopyContext createWorkdirContext, File workdir) throws Exception { if (!workdirIsCached) { IOUtil.delete(workdir); } @@ -78,7 +77,7 @@ public class SimpleWorkdirFactoryTest { public void shutdown() { } }; - simpleWorkdirFactory = new SimpleWorkdirFactory(configurableTestWorkdirProvider) { + simpleWorkingCopyFactory = new SimpleWorkingCopyFactory(configurableTestWorkingCopyPool) { @Override protected Repository getScmRepository(Context context) { return REPOSITORY; @@ -95,8 +94,8 @@ public class SimpleWorkdirFactoryTest { } @Override - protected void closeWorkdirInternal(Closeable workdir) throws Exception { - workdir.close(); + protected void closeWorkingCopyInternal(Closeable workingCopy) throws Exception { + workingCopy.close(); } @Override @@ -110,7 +109,7 @@ public class SimpleWorkdirFactoryTest { @Test public void shouldCreateParentAndClone() { Context context = new Context(); - try (WorkingCopy workingCopy = simpleWorkdirFactory.createWorkingCopy(context, null)) { + try (WorkingCopy workingCopy = simpleWorkingCopyFactory.createWorkingCopy(context, null)) { assertThat(workingCopy.getCentralRepository()).isSameAs(parent); assertThat(workingCopy.getWorkingRepository()).isSameAs(clone); } @@ -119,7 +118,7 @@ public class SimpleWorkdirFactoryTest { @Test public void shouldCloseParent() throws IOException { Context context = new Context(); - try (WorkingCopy workingCopy = simpleWorkdirFactory.createWorkingCopy(context, null)) {} + try (WorkingCopy workingCopy = simpleWorkingCopyFactory.createWorkingCopy(context, null)) {} verify(parent).close(); } @@ -127,7 +126,7 @@ public class SimpleWorkdirFactoryTest { @Test public void shouldCloseClone() throws IOException { Context context = new Context(); - try (WorkingCopy workingCopy = simpleWorkdirFactory.createWorkingCopy(context, null)) {} + try (WorkingCopy workingCopy = simpleWorkingCopyFactory.createWorkingCopy(context, null)) {} verify(clone).close(); } @@ -135,7 +134,7 @@ public class SimpleWorkdirFactoryTest { @Test public void shouldDeleteWorkdirIfNotCached() { Context context = new Context(); - try (WorkingCopy workingCopy = simpleWorkdirFactory.createWorkingCopy(context, null)) {} + try (WorkingCopy workingCopy = simpleWorkingCopyFactory.createWorkingCopy(context, null)) {} assertThat(workdir).doesNotExist(); } @@ -144,7 +143,7 @@ public class SimpleWorkdirFactoryTest { public void shouldNotDeleteWorkdirIfCached() { Context context = new Context(); workdirIsCached = true; - try (WorkingCopy workingCopy = simpleWorkdirFactory.createWorkingCopy(context, null)) {} + try (WorkingCopy workingCopy = simpleWorkingCopyFactory.createWorkingCopy(context, null)) {} assertThat(workdir).exists(); } @@ -152,7 +151,7 @@ public class SimpleWorkdirFactoryTest { @Test public void shouldPropagateInitialBranch() { Context context = new Context(); - try (WorkingCopy workingCopy = simpleWorkdirFactory.createWorkingCopy(context, "some")) { + try (WorkingCopy workingCopy = simpleWorkingCopyFactory.createWorkingCopy(context, "some")) { assertThat(initialBranchForLastCloneCall).isEqualTo("some"); } } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryHandler.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryHandler.java index d977cb242f..2760f59794 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryHandler.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryHandler.java @@ -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; //~--- non-JDK imports -------------------------------------------------------- @@ -83,7 +83,7 @@ public class GitRepositoryHandler private final Scheduler scheduler; - private final GitWorkdirFactory workdirFactory; + private final GitWorkingCopyFactory workingCopyFactory; private Task task; @@ -93,12 +93,12 @@ public class GitRepositoryHandler public GitRepositoryHandler(ConfigurationStoreFactory storeFactory, Scheduler scheduler, RepositoryLocationResolver repositoryLocationResolver, - GitWorkdirFactory workdirFactory, + GitWorkingCopyFactory workingCopyFactory, PluginLoader pluginLoader) { super(storeFactory, repositoryLocationResolver, pluginLoader); this.scheduler = scheduler; - this.workdirFactory = workdirFactory; + this.workingCopyFactory = workingCopyFactory; } //~--- get methods ---------------------------------------------------------- @@ -169,8 +169,8 @@ public class GitRepositoryHandler return getStringFromResource(RESOURCE_VERSION, DEFAULT_VERSION_INFORMATION); } - public GitWorkdirFactory getWorkdirFactory() { - return workdirFactory; + public GitWorkingCopyFactory getWorkingCopyFactory() { + return workingCopyFactory; } public String getRepositoryId(StoredConfig gitConfig) { diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitWorkdirFactory.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitWorkingCopyFactory.java similarity index 89% rename from scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitWorkdirFactory.java rename to scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitWorkingCopyFactory.java index bb9f40132d..7585d2824f 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitWorkdirFactory.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitWorkingCopyFactory.java @@ -21,12 +21,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.repository; import org.eclipse.jgit.lib.Repository; import sonia.scm.repository.spi.GitContext; -import sonia.scm.repository.util.WorkdirFactory; +import sonia.scm.repository.util.WorkingCopyFactory; -public interface GitWorkdirFactory extends WorkdirFactory { +public interface GitWorkingCopyFactory extends WorkingCopyFactory { } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/AbstractGitCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/AbstractGitCommand.java index 4f3e31f4d7..11e2040f57 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/AbstractGitCommand.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/AbstractGitCommand.java @@ -42,7 +42,7 @@ import org.eclipse.jgit.transport.RemoteRefUpdate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sonia.scm.repository.GitUtil; -import sonia.scm.repository.GitWorkdirFactory; +import sonia.scm.repository.GitWorkingCopyFactory; import sonia.scm.repository.InternalRepositoryException; import sonia.scm.repository.Person; import sonia.scm.repository.util.WorkingCopy; @@ -135,8 +135,8 @@ class AbstractGitCommand } } - > R inClone(Function workerSupplier, GitWorkdirFactory workdirFactory, String initialBranch) { - try (WorkingCopy workingCopy = workdirFactory.createWorkingCopy(context, initialBranch)) { + > R inClone(Function workerSupplier, GitWorkingCopyFactory workingCopyFactory, String initialBranch) { + try (WorkingCopy workingCopy = workingCopyFactory.createWorkingCopy(context, initialBranch)) { Repository repository = workingCopy.getWorkingRepository(); logger.debug("cloned repository to folder {}", repository.getWorkTree()); return workerSupplier.apply(new Git(repository)).run(); diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitMergeCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitMergeCommand.java index 5f915535b1..9f362edeb6 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitMergeCommand.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitMergeCommand.java @@ -36,7 +36,7 @@ import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.merge.ResolveMerger; import org.eclipse.jgit.treewalk.CanonicalTreeParser; import org.eclipse.jgit.treewalk.filter.PathFilter; -import sonia.scm.repository.GitWorkdirFactory; +import sonia.scm.repository.GitWorkingCopyFactory; import sonia.scm.repository.InternalRepositoryException; import sonia.scm.repository.api.MergeCommandResult; import sonia.scm.repository.api.MergeDryRunCommandResult; @@ -53,7 +53,7 @@ import static sonia.scm.NotFoundException.notFound; public class GitMergeCommand extends AbstractGitCommand implements MergeCommand { - private final GitWorkdirFactory workdirFactory; + private final GitWorkingCopyFactory workingCopyFactory; private static final Set STRATEGIES = ImmutableSet.of( MergeStrategy.MERGE_COMMIT, @@ -61,9 +61,9 @@ public class GitMergeCommand extends AbstractGitCommand implements MergeCommand MergeStrategy.SQUASH ); - GitMergeCommand(GitContext context, GitWorkdirFactory workdirFactory) { + GitMergeCommand(GitContext context, GitWorkingCopyFactory workingCopyFactory) { super(context); - this.workdirFactory = workdirFactory; + this.workingCopyFactory = workingCopyFactory; } @Override @@ -73,19 +73,19 @@ public class GitMergeCommand extends AbstractGitCommand implements MergeCommand @Override public MergeConflictResult computeConflicts(MergeCommandRequest request) { - return inClone(git -> new ConflictWorker(git, request), workdirFactory, request.getTargetBranch()); + return inClone(git -> new ConflictWorker(git, request), workingCopyFactory, request.getTargetBranch()); } private MergeCommandResult mergeWithStrategy(MergeCommandRequest request) { switch(request.getMergeStrategy()) { case SQUASH: - return inClone(clone -> new GitMergeWithSquash(clone, request, context, repository), workdirFactory, request.getTargetBranch()); + return inClone(clone -> new GitMergeWithSquash(clone, request, context, repository), workingCopyFactory, request.getTargetBranch()); case FAST_FORWARD_IF_POSSIBLE: - return inClone(clone -> new GitFastForwardIfPossible(clone, request, context, repository), workdirFactory, request.getTargetBranch()); + return inClone(clone -> new GitFastForwardIfPossible(clone, request, context, repository), workingCopyFactory, request.getTargetBranch()); case MERGE_COMMIT: - return inClone(clone -> new GitMergeCommit(clone, request, context, repository), workdirFactory, request.getTargetBranch()); + return inClone(clone -> new GitMergeCommit(clone, request, context, repository), workingCopyFactory, request.getTargetBranch()); default: throw new MergeStrategyNotSupportedException(repository, request.getMergeStrategy()); diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitModifyCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitModifyCommand.java index d808434c1d..9e0f5449d3 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitModifyCommand.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitModifyCommand.java @@ -34,7 +34,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sonia.scm.ConcurrentModificationException; import sonia.scm.NoChangesMadeException; -import sonia.scm.repository.GitWorkdirFactory; +import sonia.scm.repository.GitWorkingCopyFactory; import sonia.scm.repository.InternalRepositoryException; import sonia.scm.repository.Repository; import sonia.scm.web.lfs.LfsBlobStoreFactory; @@ -50,18 +50,18 @@ public class GitModifyCommand extends AbstractGitCommand implements ModifyComman private static final Logger LOG = LoggerFactory.getLogger(GitModifyCommand.class); private static final Striped REGISTER_LOCKS = Striped.lock(5); - private final GitWorkdirFactory workdirFactory; + private final GitWorkingCopyFactory workingCopyFactory; private final LfsBlobStoreFactory lfsBlobStoreFactory; - GitModifyCommand(GitContext context, GitWorkdirFactory workdirFactory, LfsBlobStoreFactory lfsBlobStoreFactory) { + GitModifyCommand(GitContext context, GitWorkingCopyFactory workingCopyFactory, LfsBlobStoreFactory lfsBlobStoreFactory) { super(context); - this.workdirFactory = workdirFactory; + this.workingCopyFactory = workingCopyFactory; this.lfsBlobStoreFactory = lfsBlobStoreFactory; } @Override public String execute(ModifyCommandRequest request) { - return inClone(clone -> new ModifyWorker(clone, request), workdirFactory, request.getBranch()); + return inClone(clone -> new ModifyWorker(clone, request), workingCopyFactory, request.getBranch()); } private class ModifyWorker extends GitCloneWorker implements ModifyWorkerHelper { diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java index 4aa6ab3a08..862631c32c 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java @@ -264,12 +264,12 @@ public class GitRepositoryServiceProvider extends RepositoryServiceProvider @Override public MergeCommand getMergeCommand() { - return new GitMergeCommand(context, handler.getWorkdirFactory()); + return new GitMergeCommand(context, handler.getWorkingCopyFactory()); } @Override public ModifyCommand getModifyCommand() { - return new GitModifyCommand(context, handler.getWorkdirFactory(), lfsBlobStoreFactory); + return new GitModifyCommand(context, handler.getWorkingCopyFactory(), lfsBlobStoreFactory); } @Override diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/SimpleGitWorkdirFactory.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactory.java similarity index 89% rename from scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/SimpleGitWorkdirFactory.java rename to scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactory.java index e75b8775cc..e752042d74 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/SimpleGitWorkdirFactory.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactory.java @@ -34,10 +34,10 @@ import org.eclipse.jgit.transport.ScmTransportProtocol; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sonia.scm.repository.GitUtil; -import sonia.scm.repository.GitWorkdirFactory; +import sonia.scm.repository.GitWorkingCopyFactory; import sonia.scm.repository.InternalRepositoryException; -import sonia.scm.repository.util.CacheSupportingWorkdirProvider; -import sonia.scm.repository.util.SimpleWorkdirFactory; +import sonia.scm.repository.util.WorkingCopyPool; +import sonia.scm.repository.util.SimpleWorkingCopyFactory; import sonia.scm.util.SystemUtil; import javax.inject.Inject; @@ -47,12 +47,12 @@ import java.io.IOException; import static sonia.scm.ContextEntry.ContextBuilder.entity; import static sonia.scm.NotFoundException.notFound; -public class SimpleGitWorkdirFactory extends SimpleWorkdirFactory implements GitWorkdirFactory { +public class SimpleGitWorkingCopyFactory extends SimpleWorkingCopyFactory implements GitWorkingCopyFactory { - private static final Logger LOG = LoggerFactory.getLogger(SimpleGitWorkdirFactory.class); + private static final Logger LOG = LoggerFactory.getLogger(SimpleGitWorkingCopyFactory.class); @Inject - public SimpleGitWorkdirFactory(CacheSupportingWorkdirProvider workdirProvider) { + public SimpleGitWorkingCopyFactory(WorkingCopyPool workdirProvider) { super(workdirProvider); } @@ -124,9 +124,9 @@ public class SimpleGitWorkdirFactory extends SimpleWorkdirFactory interceptor) { - return new GitMergeCommand(createContext(), new SimpleGitWorkdirFactory(new NoneCachingWorkdirProvider(new WorkdirProvider()))) { + return new GitMergeCommand(createContext(), new SimpleGitWorkingCopyFactory(new NoneCachingWorkingCopyPool(new WorkdirProvider()))) { @Override - > R inClone(Function workerSupplier, GitWorkdirFactory workdirFactory, String initialBranch) { + > R inClone(Function workerSupplier, GitWorkingCopyFactory workingCopyFactory, String initialBranch) { Function interceptedWorkerSupplier = git -> { interceptor.accept(git); return workerSupplier.apply(git); }; - return super.inClone(interceptedWorkerSupplier, workdirFactory, initialBranch); + return super.inClone(interceptedWorkerSupplier, workingCopyFactory, initialBranch); } }; } diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitMergeCommand_Conflict_Test.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitMergeCommand_Conflict_Test.java index fc0a457a29..1581e2ec08 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitMergeCommand_Conflict_Test.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitMergeCommand_Conflict_Test.java @@ -27,7 +27,7 @@ package sonia.scm.repository.spi; import org.junit.Rule; import org.junit.Test; import sonia.scm.repository.spi.MergeConflictResult.SingleMergeConflict; -import sonia.scm.repository.util.NoneCachingWorkdirProvider; +import sonia.scm.repository.util.NoneCachingWorkingCopyPool; import sonia.scm.repository.util.WorkdirProvider; import java.io.IOException; @@ -92,7 +92,7 @@ public class GitMergeCommand_Conflict_Test extends AbstractGitCommandTestBase { } private MergeConflictResult computeMergeConflictResult(String branchToMerge, String targetBranch) { - GitMergeCommand gitMergeCommand = new GitMergeCommand(createContext(), new SimpleGitWorkdirFactory(new NoneCachingWorkdirProvider(new WorkdirProvider()))); + GitMergeCommand gitMergeCommand = new GitMergeCommand(createContext(), new SimpleGitWorkingCopyFactory(new NoneCachingWorkingCopyPool(new WorkdirProvider()))); MergeCommandRequest mergeCommandRequest = new MergeCommandRequest(); mergeCommandRequest.setBranchToMerge(branchToMerge); mergeCommandRequest.setTargetBranch(targetBranch); diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommandTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommandTest.java index 2f53b25a71..23799071b4 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommandTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommandTest.java @@ -42,7 +42,7 @@ import sonia.scm.BadRequestException; import sonia.scm.ConcurrentModificationException; import sonia.scm.NotFoundException; import sonia.scm.repository.Person; -import sonia.scm.repository.util.NoneCachingWorkdirProvider; +import sonia.scm.repository.util.NoneCachingWorkingCopyPool; import sonia.scm.repository.util.WorkdirProvider; import sonia.scm.web.lfs.LfsBlobStoreFactory; @@ -324,7 +324,7 @@ public class GitModifyCommandTest extends AbstractGitCommandTestBase { } private GitModifyCommand createCommand() { - return new GitModifyCommand(createContext(), new SimpleGitWorkdirFactory(new NoneCachingWorkdirProvider(new WorkdirProvider())), lfsBlobStoreFactory); + return new GitModifyCommand(createContext(), new SimpleGitWorkingCopyFactory(new NoneCachingWorkingCopyPool(new WorkdirProvider())), lfsBlobStoreFactory); } @FunctionalInterface diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_LFSTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_LFSTest.java index 293c251a23..df3f2689a0 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_LFSTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_LFSTest.java @@ -35,7 +35,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import sonia.scm.repository.Person; -import sonia.scm.repository.util.NoneCachingWorkdirProvider; +import sonia.scm.repository.util.NoneCachingWorkingCopyPool; import sonia.scm.repository.util.WorkdirProvider; import sonia.scm.store.Blob; import sonia.scm.store.BlobStore; @@ -131,7 +131,7 @@ public class GitModifyCommand_LFSTest extends AbstractGitCommandTestBase { } private GitModifyCommand createCommand() { - return new GitModifyCommand(createContext(), new SimpleGitWorkdirFactory(new NoneCachingWorkdirProvider(new WorkdirProvider())), lfsBlobStoreFactory); + return new GitModifyCommand(createContext(), new SimpleGitWorkingCopyFactory(new NoneCachingWorkingCopyPool(new WorkdirProvider())), lfsBlobStoreFactory); } @Override diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_withEmptyRepositoryTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_withEmptyRepositoryTest.java index e339817d0d..bf6d255538 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_withEmptyRepositoryTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_withEmptyRepositoryTest.java @@ -38,7 +38,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import sonia.scm.repository.Person; -import sonia.scm.repository.util.NoneCachingWorkdirProvider; +import sonia.scm.repository.util.NoneCachingWorkingCopyPool; import sonia.scm.repository.util.WorkdirProvider; import sonia.scm.web.lfs.LfsBlobStoreFactory; @@ -102,7 +102,7 @@ public class GitModifyCommand_withEmptyRepositoryTest extends AbstractGitCommand } private GitModifyCommand createCommand() { - return new GitModifyCommand(createContext(), new SimpleGitWorkdirFactory(new NoneCachingWorkdirProvider(new WorkdirProvider())), lfsBlobStoreFactory); + return new GitModifyCommand(createContext(), new SimpleGitWorkingCopyFactory(new NoneCachingWorkingCopyPool(new WorkdirProvider())), lfsBlobStoreFactory); } @FunctionalInterface diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/SimpleGitWorkdirFactoryTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactoryTest.java similarity index 83% rename from scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/SimpleGitWorkdirFactoryTest.java rename to scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactoryTest.java index b9e4e1fd75..868c96c023 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/SimpleGitWorkdirFactoryTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactoryTest.java @@ -38,7 +38,7 @@ import sonia.scm.repository.GitRepositoryHandler; import sonia.scm.repository.PreProcessorUtil; import sonia.scm.repository.RepositoryManager; import sonia.scm.repository.api.HookContextFactory; -import sonia.scm.repository.util.NoneCachingWorkdirProvider; +import sonia.scm.repository.util.NoneCachingWorkingCopyPool; import sonia.scm.repository.util.WorkdirProvider; import sonia.scm.repository.util.WorkingCopy; @@ -51,7 +51,7 @@ import static com.google.inject.util.Providers.of; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; -public class SimpleGitWorkdirFactoryTest extends AbstractGitCommandTestBase { +public class SimpleGitWorkingCopyFactoryTest extends AbstractGitCommandTestBase { @Rule public TemporaryFolder temporaryFolder = new TemporaryFolder(); @@ -72,7 +72,7 @@ public class SimpleGitWorkdirFactoryTest extends AbstractGitCommandTestBase { @Test public void emptyPoolShouldCreateNewWorkdir() { - SimpleGitWorkdirFactory factory = new SimpleGitWorkdirFactory(new NoneCachingWorkdirProvider(workdirProvider)); + SimpleGitWorkingCopyFactory factory = new SimpleGitWorkingCopyFactory(new NoneCachingWorkingCopyPool(workdirProvider)); File masterRepo = createRepositoryDirectory(); try (WorkingCopy workingCopy = factory.createWorkingCopy(createContext(), null)) { @@ -90,7 +90,7 @@ public class SimpleGitWorkdirFactoryTest extends AbstractGitCommandTestBase { @Test public void shouldCheckoutInitialBranch() { - SimpleGitWorkdirFactory factory = new SimpleGitWorkdirFactory(new NoneCachingWorkdirProvider(workdirProvider)); + SimpleGitWorkingCopyFactory factory = new SimpleGitWorkingCopyFactory(new NoneCachingWorkingCopyPool(workdirProvider)); try (WorkingCopy workingCopy = factory.createWorkingCopy(createContext(), "test-branch")) { assertThat(new File(workingCopy.getWorkingRepository().getWorkTree(), "a.txt")) @@ -102,7 +102,7 @@ public class SimpleGitWorkdirFactoryTest extends AbstractGitCommandTestBase { @Test public void shouldCheckoutDefaultBranch() { - SimpleGitWorkdirFactory factory = new SimpleGitWorkdirFactory(new NoneCachingWorkdirProvider(workdirProvider)); + SimpleGitWorkingCopyFactory factory = new SimpleGitWorkingCopyFactory(new NoneCachingWorkingCopyPool(workdirProvider)); try (WorkingCopy workingCopy = factory.createWorkingCopy(createContext(), null)) { assertThat(new File(workingCopy.getWorkingRepository().getWorkTree(), "a.txt")) @@ -114,7 +114,7 @@ public class SimpleGitWorkdirFactoryTest extends AbstractGitCommandTestBase { @Test public void cloneFromPoolShouldNotBeReused() { - SimpleGitWorkdirFactory factory = new SimpleGitWorkdirFactory(new NoneCachingWorkdirProvider(workdirProvider)); + SimpleGitWorkingCopyFactory factory = new SimpleGitWorkingCopyFactory(new NoneCachingWorkingCopyPool(workdirProvider)); File firstDirectory; try (WorkingCopy workingCopy = factory.createWorkingCopy(createContext(), null)) { @@ -128,7 +128,7 @@ public class SimpleGitWorkdirFactoryTest extends AbstractGitCommandTestBase { @Test public void cloneFromPoolShouldBeDeletedOnClose() { - SimpleGitWorkdirFactory factory = new SimpleGitWorkdirFactory(new NoneCachingWorkdirProvider(workdirProvider)); + SimpleGitWorkingCopyFactory factory = new SimpleGitWorkingCopyFactory(new NoneCachingWorkingCopyPool(workdirProvider)); File directory; try (WorkingCopy workingCopy = factory.createWorkingCopy(createContext(), null)) { @@ -139,7 +139,7 @@ public class SimpleGitWorkdirFactoryTest extends AbstractGitCommandTestBase { @Test public void shouldReclaimCleanDirectoryWithSameBranch() throws Exception { - SimpleGitWorkdirFactory factory = new SimpleGitWorkdirFactory(new NoneCachingWorkdirProvider(workdirProvider)); + SimpleGitWorkingCopyFactory factory = new SimpleGitWorkingCopyFactory(new NoneCachingWorkingCopyPool(workdirProvider)); File workdir = createExistingClone(factory); factory.reclaimRepository(createContext(), workdir, "master"); @@ -149,7 +149,7 @@ public class SimpleGitWorkdirFactoryTest extends AbstractGitCommandTestBase { @Test public void shouldReclaimCleanDirectoryWithOtherBranch() throws Exception { - SimpleGitWorkdirFactory factory = new SimpleGitWorkdirFactory(new NoneCachingWorkdirProvider(workdirProvider)); + SimpleGitWorkingCopyFactory factory = new SimpleGitWorkingCopyFactory(new NoneCachingWorkingCopyPool(workdirProvider)); File workdir = createExistingClone(factory); factory.reclaimRepository(createContext(), workdir, "test-branch"); @@ -159,7 +159,7 @@ public class SimpleGitWorkdirFactoryTest extends AbstractGitCommandTestBase { @Test public void shouldReclaimDirectoryWithDeletedFileInIndex() throws Exception { - SimpleGitWorkdirFactory factory = new SimpleGitWorkdirFactory(new NoneCachingWorkdirProvider(workdirProvider)); + SimpleGitWorkingCopyFactory factory = new SimpleGitWorkingCopyFactory(new NoneCachingWorkingCopyPool(workdirProvider)); File workdir = createExistingClone(factory); Git.open(workdir).rm().addFilepattern("a.txt").call(); @@ -170,7 +170,7 @@ public class SimpleGitWorkdirFactoryTest extends AbstractGitCommandTestBase { @Test public void shouldReclaimDirectoryWithDeletedFileInDirectory() throws Exception { - SimpleGitWorkdirFactory factory = new SimpleGitWorkdirFactory(new NoneCachingWorkdirProvider(workdirProvider)); + SimpleGitWorkingCopyFactory factory = new SimpleGitWorkingCopyFactory(new NoneCachingWorkingCopyPool(workdirProvider)); File workdir = createExistingClone(factory); Files.delete(workdir.toPath().resolve("a.txt")); @@ -181,7 +181,7 @@ public class SimpleGitWorkdirFactoryTest extends AbstractGitCommandTestBase { @Test public void shouldReclaimDirectoryWithAdditionalFileInDirectory() throws Exception { - SimpleGitWorkdirFactory factory = new SimpleGitWorkdirFactory(new NoneCachingWorkdirProvider(workdirProvider)); + SimpleGitWorkingCopyFactory factory = new SimpleGitWorkingCopyFactory(new NoneCachingWorkingCopyPool(workdirProvider)); File workdir = createExistingClone(factory); Path newDirectory = workdir.toPath().resolve("new"); Files.createDirectories(newDirectory); @@ -192,7 +192,7 @@ public class SimpleGitWorkdirFactoryTest extends AbstractGitCommandTestBase { assertBranchCheckedOutAndClean(workdir, "master"); } - public File createExistingClone(SimpleGitWorkdirFactory factory) throws Exception { + public File createExistingClone(SimpleGitWorkingCopyFactory factory) throws Exception { File workdir = temporaryFolder.newFolder(); extract(workdir, "sonia/scm/repository/spi/scm-git-spi-test-workdir.zip"); Git.open(workdir).remoteSetUrl().setRemoteUri(new URIish(factory.createScmTransportProtocolUri(repositoryDirectory))).setRemoteName("origin").call(); diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgRepositoryHandler.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgRepositoryHandler.java index 386483a43a..6c33607750 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgRepositoryHandler.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgRepositoryHandler.java @@ -42,7 +42,7 @@ import sonia.scm.io.INISection; import sonia.scm.plugin.Extension; import sonia.scm.plugin.PluginLoader; import sonia.scm.repository.spi.HgRepositoryServiceProvider; -import sonia.scm.repository.spi.HgWorkdirFactory; +import sonia.scm.repository.spi.HgWorkingCopyFactory; import sonia.scm.store.ConfigurationStoreFactory; import sonia.scm.util.IOUtil; import sonia.scm.util.SystemUtil; @@ -78,7 +78,7 @@ public class HgRepositoryHandler private final Provider hgContextProvider; - private final HgWorkdirFactory workdirFactory; + private final HgWorkingCopyFactory workingCopyFactory; private final JAXBContext jaxbContext; @@ -86,10 +86,10 @@ public class HgRepositoryHandler public HgRepositoryHandler(ConfigurationStoreFactory storeFactory, Provider hgContextProvider, RepositoryLocationResolver repositoryLocationResolver, - PluginLoader pluginLoader, HgWorkdirFactory workdirFactory) { + PluginLoader pluginLoader, HgWorkingCopyFactory workingCopyFactory) { super(storeFactory, repositoryLocationResolver, pluginLoader); this.hgContextProvider = hgContextProvider; - this.workdirFactory = workdirFactory; + this.workingCopyFactory = workingCopyFactory; try { @@ -259,8 +259,8 @@ public class HgRepositoryHandler } } - public HgWorkdirFactory getWorkdirFactory() { - return workdirFactory; + public HgWorkingCopyFactory getWorkingCopyFactory() { + return workingCopyFactory; } public JAXBContext getJaxbContext() { diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgBranchCommand.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgBranchCommand.java index 408daedd81..704e68343c 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgBranchCommand.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgBranchCommand.java @@ -45,16 +45,16 @@ public class HgBranchCommand extends AbstractCommand implements BranchCommand { private static final Logger LOG = LoggerFactory.getLogger(HgBranchCommand.class); - private final HgWorkdirFactory workdirFactory; + private final HgWorkingCopyFactory workingCopyFactory; - HgBranchCommand(HgCommandContext context, HgWorkdirFactory workdirFactory) { + HgBranchCommand(HgCommandContext context, HgWorkingCopyFactory workingCopyFactory) { super(context); - this.workdirFactory = workdirFactory; + this.workingCopyFactory = workingCopyFactory; } @Override public Branch branch(BranchRequest request) { - try (WorkingCopy workingCopy = workdirFactory.createWorkingCopy(getContext(), request.getParentBranch())) { + try (WorkingCopy workingCopy = workingCopyFactory.createWorkingCopy(getContext(), request.getParentBranch())) { com.aragost.javahg.Repository repository = workingCopy.getWorkingRepository(); Changeset emptyChangeset = createNewBranchWithEmptyCommit(request, repository); @@ -70,7 +70,7 @@ public class HgBranchCommand extends AbstractCommand implements BranchCommand { @Override public void deleteOrClose(String branchName) { - try (WorkingCopy workingCopy = workdirFactory.createWorkingCopy(getContext(), branchName)) { + try (WorkingCopy workingCopy = workingCopyFactory.createWorkingCopy(getContext(), branchName)) { User currentUser = SecurityUtils.getSubject().getPrincipals().oneByType(User.class); LOG.debug("Closing branch '{}' in repository {}", branchName, getRepository().getNamespaceAndName()); @@ -104,7 +104,7 @@ public class HgBranchCommand extends AbstractCommand implements BranchCommand { private void pullChangesIntoCentralRepository(WorkingCopy workingCopy, String branch) { try { PullCommand pullCommand = PullCommand.on(workingCopy.getCentralRepository()); - workdirFactory.configure(pullCommand); + workingCopyFactory.configure(pullCommand); pullCommand.execute(workingCopy.getDirectory().getAbsolutePath()); } catch (Exception e) { // TODO handle failed update diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgModifyCommand.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgModifyCommand.java index 8e63c5b3c8..ea496fe74c 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgModifyCommand.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgModifyCommand.java @@ -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; import com.aragost.javahg.Changeset; @@ -43,17 +43,17 @@ import java.util.List; public class HgModifyCommand implements ModifyCommand { private HgCommandContext context; - private final HgWorkdirFactory workdirFactory; + private final HgWorkingCopyFactory workingCopyFactory; - public HgModifyCommand(HgCommandContext context, HgWorkdirFactory workdirFactory) { + public HgModifyCommand(HgCommandContext context, HgWorkingCopyFactory workingCopyFactory) { this.context = context; - this.workdirFactory = workdirFactory; + this.workingCopyFactory = workingCopyFactory; } @Override public String execute(ModifyCommandRequest request) { - try (WorkingCopy workingCopy = workdirFactory.createWorkingCopy(context, request.getBranch())) { + try (WorkingCopy workingCopy = workingCopyFactory.createWorkingCopy(context, request.getBranch())) { Repository workingRepository = workingCopy.getWorkingRepository(); request.getRequests().forEach( partialRequest -> { @@ -112,7 +112,7 @@ public class HgModifyCommand implements ModifyCommand { private List pullModifyChangesToCentralRepository(ModifyCommandRequest request, WorkingCopy workingCopy) { try { com.aragost.javahg.commands.PullCommand pullCommand = PullCommand.on(workingCopy.getCentralRepository()); - workdirFactory.configure(pullCommand); + workingCopyFactory.configure(pullCommand); return pullCommand.execute(workingCopy.getDirectory().getAbsolutePath()); } catch (Exception e) { throw new IntegrateChangesFromWorkdirException(context.getScmRepository(), diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java index 3995146e42..ce64b06982 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java @@ -120,7 +120,7 @@ public class HgRepositoryServiceProvider extends RepositoryServiceProvider @Override public BranchCommand getBranchCommand() { - return new HgBranchCommand(context, handler.getWorkdirFactory()); + return new HgBranchCommand(context, handler.getWorkingCopyFactory()); } /** @@ -232,7 +232,7 @@ public class HgRepositoryServiceProvider extends RepositoryServiceProvider @Override public ModifyCommand getModifyCommand() { - return new HgModifyCommand(context, handler.getWorkdirFactory()); + return new HgModifyCommand(context, handler.getWorkingCopyFactory()); } /** diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgWorkdirFactory.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgWorkingCopyFactory.java similarity index 89% rename from scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgWorkdirFactory.java rename to scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgWorkingCopyFactory.java index e4c816cb0c..1dfc938493 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgWorkdirFactory.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgWorkingCopyFactory.java @@ -21,13 +21,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.repository.spi; import com.aragost.javahg.Repository; import com.aragost.javahg.commands.PullCommand; -import sonia.scm.repository.util.WorkdirFactory; +import sonia.scm.repository.util.WorkingCopyFactory; -public interface HgWorkdirFactory extends WorkdirFactory { +public interface HgWorkingCopyFactory extends WorkingCopyFactory { void configure(PullCommand pullCommand); } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkdirFactory.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactory.java similarity index 87% rename from scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkdirFactory.java rename to scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactory.java index 85f4a7bd4f..d84e6e163c 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkdirFactory.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactory.java @@ -30,24 +30,23 @@ import com.aragost.javahg.commands.CloneCommand; import com.aragost.javahg.commands.PullCommand; import com.aragost.javahg.commands.UpdateCommand; import com.aragost.javahg.commands.flags.CloneCommandFlags; -import sonia.scm.repository.util.CacheSupportingWorkdirProvider; -import sonia.scm.repository.util.SimpleWorkdirFactory; +import sonia.scm.repository.util.WorkingCopyPool; +import sonia.scm.repository.util.SimpleWorkingCopyFactory; import sonia.scm.web.HgRepositoryEnvironmentBuilder; import javax.inject.Inject; import javax.inject.Provider; -import javax.servlet.ServletContextEvent; import java.io.File; import java.io.IOException; import java.util.Map; import java.util.function.BiConsumer; -public class SimpleHgWorkdirFactory extends SimpleWorkdirFactory implements HgWorkdirFactory { +public class SimpleHgWorkingCopyFactory extends SimpleWorkingCopyFactory implements HgWorkingCopyFactory { private final Provider hgRepositoryEnvironmentBuilder; @Inject - public SimpleHgWorkdirFactory(Provider hgRepositoryEnvironmentBuilder, CacheSupportingWorkdirProvider workdirProvider) { + public SimpleHgWorkingCopyFactory(Provider hgRepositoryEnvironmentBuilder, WorkingCopyPool workdirProvider) { super(workdirProvider); this.hgRepositoryEnvironmentBuilder = hgRepositoryEnvironmentBuilder; } @@ -85,8 +84,8 @@ public class SimpleHgWorkdirFactory extends SimpleWorkdirFactory b.getName().equals("new_branch")).isNotEmpty(); assertThat(cmdContext.open().changeset(newBranch.getRevision()).getParent1().getBranch()).isEqualTo("default"); @@ -75,7 +75,7 @@ public class HgBranchCommandTest extends AbstractHgCommandTestBase { branchRequest.setParentBranch("test-branch"); branchRequest.setNewBranch("new_branch"); - Branch newBranch = new HgBranchCommand(cmdContext, workdirFactory).branch(branchRequest); + Branch newBranch = new HgBranchCommand(cmdContext, workingCopyFactory).branch(branchRequest); assertThat(readBranches()).filteredOn(b -> b.getName().equals("new_branch")).isNotEmpty(); assertThat(cmdContext.open().changeset(newBranch.getRevision()).getParent1().getBranch()).isEqualTo("test-branch"); @@ -85,7 +85,7 @@ public class HgBranchCommandTest extends AbstractHgCommandTestBase { public void shouldCloseBranch() { String branchToBeClosed = "test-branch"; - new HgBranchCommand(cmdContext, workdirFactory).deleteOrClose(branchToBeClosed); + new HgBranchCommand(cmdContext, workingCopyFactory).deleteOrClose(branchToBeClosed); assertThat(readBranches()).filteredOn(b -> b.getName().equals(branchToBeClosed)).isEmpty(); } @@ -93,8 +93,8 @@ public class HgBranchCommandTest extends AbstractHgCommandTestBase { public void shouldThrowInternalRepositoryException() { String branchToBeClosed = "default"; - new HgBranchCommand(cmdContext, workdirFactory).deleteOrClose(branchToBeClosed); - assertThrows(InternalRepositoryException.class, () -> new HgBranchCommand(cmdContext, workdirFactory).deleteOrClose(branchToBeClosed)); + new HgBranchCommand(cmdContext, workingCopyFactory).deleteOrClose(branchToBeClosed); + assertThrows(InternalRepositoryException.class, () -> new HgBranchCommand(cmdContext, workingCopyFactory).deleteOrClose(branchToBeClosed)); } private List readBranches() { diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgModifyCommandTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgModifyCommandTest.java index 6cbc647447..872151ab6b 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgModifyCommandTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgModifyCommandTest.java @@ -35,7 +35,7 @@ import sonia.scm.NotFoundException; import sonia.scm.repository.HgHookManager; import sonia.scm.repository.HgTestUtil; import sonia.scm.repository.Person; -import sonia.scm.repository.util.NoneCachingWorkdirProvider; +import sonia.scm.repository.util.NoneCachingWorkingCopyPool; import sonia.scm.repository.util.WorkdirProvider; import sonia.scm.web.HgRepositoryEnvironmentBuilder; @@ -56,13 +56,13 @@ public class HgModifyCommandTest extends AbstractHgCommandTestBase { public void initHgModifyCommand() { HgHookManager hookManager = HgTestUtil.createHookManager(); HgRepositoryEnvironmentBuilder environmentBuilder = new HgRepositoryEnvironmentBuilder(handler, hookManager); - SimpleHgWorkdirFactory workdirFactory = new SimpleHgWorkdirFactory(Providers.of(environmentBuilder), new NoneCachingWorkdirProvider(new WorkdirProvider())) { + SimpleHgWorkingCopyFactory workingCopyFactory = new SimpleHgWorkingCopyFactory(Providers.of(environmentBuilder), new NoneCachingWorkingCopyPool(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 + hgModifyCommand = new HgModifyCommand(cmdContext, workingCopyFactory ); } diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnWorkDirFactory.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnWorkingCopyFactory.java similarity index 89% rename from scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnWorkDirFactory.java rename to scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnWorkingCopyFactory.java index c7969ed5a9..0c87f2d359 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnWorkDirFactory.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnWorkingCopyFactory.java @@ -21,13 +21,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.repository; import sonia.scm.repository.spi.SvnContext; -import sonia.scm.repository.util.WorkdirFactory; +import sonia.scm.repository.util.WorkingCopyFactory; import java.io.File; -public interface SvnWorkDirFactory extends WorkdirFactory { +public interface SvnWorkingCopyFactory extends WorkingCopyFactory { } 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/SimpleSvnWorkingCopyFactory.java similarity index 85% rename from scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SimpleSvnWorkDirFactory.java rename to scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactory.java index c05fe6baf1..a0bfd8cd41 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/SimpleSvnWorkingCopyFactory.java @@ -29,26 +29,23 @@ import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.wc.SVNClientManager; import org.tmatesoft.svn.core.wc.SVNRevision; -import org.tmatesoft.svn.core.wc.SVNWCClient; import org.tmatesoft.svn.core.wc2.SvnCheckout; import org.tmatesoft.svn.core.wc2.SvnOperationFactory; import org.tmatesoft.svn.core.wc2.SvnTarget; import sonia.scm.repository.InternalRepositoryException; import sonia.scm.repository.Repository; -import sonia.scm.repository.SvnWorkDirFactory; -import sonia.scm.repository.util.CacheSupportingWorkdirProvider; -import sonia.scm.repository.util.SimpleWorkdirFactory; +import sonia.scm.repository.SvnWorkingCopyFactory; +import sonia.scm.repository.util.WorkingCopyPool; +import sonia.scm.repository.util.SimpleWorkingCopyFactory; import javax.inject.Inject; -import javax.servlet.ServletContextEvent; import java.io.File; -import java.io.IOException; -public class SimpleSvnWorkDirFactory extends SimpleWorkdirFactory implements SvnWorkDirFactory { +public class SimpleSvnWorkingCopyFactory extends SimpleWorkingCopyFactory implements SvnWorkingCopyFactory { @Inject - public SimpleSvnWorkDirFactory(CacheSupportingWorkdirProvider workdirProvider) { - super(workdirProvider); + public SimpleSvnWorkingCopyFactory(WorkingCopyPool workingCopyPool) { + super(workingCopyPool); } @Override @@ -99,6 +96,6 @@ public class SimpleSvnWorkDirFactory extends SimpleWorkdirFactory workingCopy = workDirFactory.createWorkingCopy(context, null)) { + try (WorkingCopy workingCopy = workingCopyFactory.createWorkingCopy(context, null)) { File workingDirectory = workingCopy.getDirectory(); modifyWorkingDirectory(request, clientManager, workingDirectory); return commitChanges(clientManager, workingDirectory, request.getCommitMessage()); 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 65879834aa..1548fba869 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 @@ -28,7 +28,7 @@ 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.SvnWorkingCopyFactory; import sonia.scm.repository.api.Command; import javax.inject.Inject; @@ -54,10 +54,10 @@ public class SvnRepositoryServiceProvider extends RepositoryServiceProvider @Inject SvnRepositoryServiceProvider(SvnRepositoryHandler handler, - Repository repository, SvnWorkDirFactory workdirFactory) + Repository repository, SvnWorkingCopyFactory workingCopyFactory) { this.context = new SvnContext(repository, handler.getDirectory(repository.getId())); - this.workDirFactory = workdirFactory; + this.workingCopyFactory = workingCopyFactory; } //~--- methods -------------------------------------------------------------- @@ -153,7 +153,7 @@ public class SvnRepositoryServiceProvider extends RepositoryServiceProvider } public ModifyCommand getModifyCommand() { - return new SvnModifyCommand(context, workDirFactory); + return new SvnModifyCommand(context, workingCopyFactory); } /** @@ -185,5 +185,5 @@ public class SvnRepositoryServiceProvider extends RepositoryServiceProvider /** Field description */ private final SvnContext context; - private final SvnWorkDirFactory workDirFactory; + private final SvnWorkingCopyFactory workingCopyFactory; } 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 c615902b3e..0a5bff15b7 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 @@ -21,25 +21,25 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.repository.spi; 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; +import sonia.scm.repository.SvnWorkingCopyFactory; @Extension public class SvnRepositoryServiceResolver implements RepositoryServiceResolver { private SvnRepositoryHandler handler; - private SvnWorkDirFactory workdirFactory; + private SvnWorkingCopyFactory workingCopyFactory; @Inject - public SvnRepositoryServiceResolver(SvnRepositoryHandler handler, SvnWorkDirFactory workdirFactory) { + public SvnRepositoryServiceResolver(SvnRepositoryHandler handler, SvnWorkingCopyFactory workingCopyFactory) { this.handler = handler; - this.workdirFactory = workdirFactory; + this.workingCopyFactory = workingCopyFactory; } @Override @@ -47,7 +47,7 @@ public class SvnRepositoryServiceResolver implements RepositoryServiceResolver { SvnRepositoryServiceProvider provider = null; if (SvnRepositoryHandler.TYPE_NAME.equalsIgnoreCase(repository.getType())) { - provider = new SvnRepositoryServiceProvider(handler, repository, workdirFactory); + provider = new SvnRepositoryServiceProvider(handler, repository, workingCopyFactory); } 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 52803adb61..078c613418 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 @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.web; import com.google.inject.servlet.ServletModule; @@ -29,8 +29,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; +import sonia.scm.repository.SvnWorkingCopyFactory; +import sonia.scm.repository.spi.SimpleSvnWorkingCopyFactory; /** * @@ -43,6 +43,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); + bind(SvnWorkingCopyFactory.class).to(SimpleSvnWorkingCopyFactory.class); } } diff --git a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SimpleSvnWorkDirFactoryTest.java b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactoryTest.java similarity index 84% rename from scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SimpleSvnWorkDirFactoryTest.java rename to scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactoryTest.java index 8f1f7b00c9..5be444aed0 100644 --- a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SimpleSvnWorkDirFactoryTest.java +++ b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactoryTest.java @@ -30,7 +30,7 @@ import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.tmatesoft.svn.core.SVNException; import sonia.scm.repository.Repository; -import sonia.scm.repository.util.NoneCachingWorkdirProvider; +import sonia.scm.repository.util.NoneCachingWorkingCopyPool; import sonia.scm.repository.util.WorkdirProvider; import sonia.scm.repository.util.WorkingCopy; @@ -39,7 +39,7 @@ import java.io.IOException; import static org.assertj.core.api.Assertions.assertThat; -public class SimpleSvnWorkDirFactoryTest extends AbstractSvnCommandTestBase { +public class SimpleSvnWorkingCopyFactoryTest extends AbstractSvnCommandTestBase { @Rule public TemporaryFolder temporaryFolder = new TemporaryFolder(); @@ -54,7 +54,7 @@ public class SimpleSvnWorkDirFactoryTest extends AbstractSvnCommandTestBase { @Test public void shouldCheckoutLatestRevision() throws SVNException, IOException { - SimpleSvnWorkDirFactory factory = new SimpleSvnWorkDirFactory(new NoneCachingWorkdirProvider(workdirProvider)); + SimpleSvnWorkingCopyFactory factory = new SimpleSvnWorkingCopyFactory(new NoneCachingWorkingCopyPool(workdirProvider)); try (WorkingCopy workingCopy = factory.createWorkingCopy(createContext(), null)) { assertThat(new File(workingCopy.getWorkingRepository(), "a.txt")) @@ -66,7 +66,7 @@ public class SimpleSvnWorkDirFactoryTest extends AbstractSvnCommandTestBase { @Test public void cloneFromPoolshouldNotBeReused() { - SimpleSvnWorkDirFactory factory = new SimpleSvnWorkDirFactory(new NoneCachingWorkdirProvider(workdirProvider)); + SimpleSvnWorkingCopyFactory factory = new SimpleSvnWorkingCopyFactory(new NoneCachingWorkingCopyPool(workdirProvider)); File firstDirectory; try (WorkingCopy workingCopy = factory.createWorkingCopy(createContext(), null)) { @@ -80,7 +80,7 @@ public class SimpleSvnWorkDirFactoryTest extends AbstractSvnCommandTestBase { @Test public void shouldDeleteCloneOnClose() { - SimpleSvnWorkDirFactory factory = new SimpleSvnWorkDirFactory(new NoneCachingWorkdirProvider(workdirProvider)); + SimpleSvnWorkingCopyFactory factory = new SimpleSvnWorkingCopyFactory(new NoneCachingWorkingCopyPool(workdirProvider)); File directory; File workingRepository; @@ -95,7 +95,7 @@ public class SimpleSvnWorkDirFactoryTest extends AbstractSvnCommandTestBase { @Test public void shouldReturnRepository() { - SimpleSvnWorkDirFactory factory = new SimpleSvnWorkDirFactory(new NoneCachingWorkdirProvider(workdirProvider)); + SimpleSvnWorkingCopyFactory factory = new SimpleSvnWorkingCopyFactory(new NoneCachingWorkingCopyPool(workdirProvider)); Repository scmRepository = factory.getScmRepository(createContext()); assertThat(scmRepository).isSameAs(repository); } 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 index 4060060ed8..029ad5cd07 100644 --- 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 @@ -33,7 +33,7 @@ import org.junit.Test; import org.junit.rules.TemporaryFolder; import sonia.scm.AlreadyExistsException; import sonia.scm.repository.Person; -import sonia.scm.repository.util.NoneCachingWorkdirProvider; +import sonia.scm.repository.util.NoneCachingWorkingCopyPool; import sonia.scm.repository.util.WorkdirProvider; import sonia.scm.repository.util.WorkingCopy; @@ -49,7 +49,7 @@ public class SvnModifyCommandTest extends AbstractSvnCommandTestBase { private SvnModifyCommand svnModifyCommand; private SvnContext context; - private SimpleSvnWorkDirFactory workDirFactory; + private SimpleSvnWorkingCopyFactory workingCopyFactory; @Rule public TemporaryFolder temporaryFolder = new TemporaryFolder(); @@ -57,8 +57,8 @@ public class SvnModifyCommandTest extends AbstractSvnCommandTestBase { @Before public void initSvnModifyCommand() { context = createContext(); - workDirFactory = new SimpleSvnWorkDirFactory(new NoneCachingWorkdirProvider(new WorkdirProvider(context.getDirectory()))); - svnModifyCommand = new SvnModifyCommand(context, workDirFactory); + workingCopyFactory = new SimpleSvnWorkingCopyFactory(new NoneCachingWorkingCopyPool(new WorkdirProvider(context.getDirectory()))); + svnModifyCommand = new SvnModifyCommand(context, workingCopyFactory); } @Before @@ -81,7 +81,7 @@ public class SvnModifyCommandTest extends AbstractSvnCommandTestBase { request.setAuthor(new Person("Arthur Dent", "dent@hitchhiker.com")); svnModifyCommand.execute(request); - WorkingCopy workingCopy = workDirFactory.createWorkingCopy(context, null); + WorkingCopy workingCopy = workingCopyFactory.createWorkingCopy(context, null); assertThat(new File(workingCopy.getWorkingRepository().getAbsolutePath() + "/a.txt")).doesNotExist(); assertThat(new File(workingCopy.getWorkingRepository().getAbsolutePath() + "/c")).exists(); } @@ -97,7 +97,7 @@ public class SvnModifyCommandTest extends AbstractSvnCommandTestBase { svnModifyCommand.execute(request); - WorkingCopy workingCopy = workDirFactory.createWorkingCopy(context, null); + WorkingCopy workingCopy = workingCopyFactory.createWorkingCopy(context, null); assertThat(new File(workingCopy.getWorkingRepository(), "Test123")).exists(); } @@ -124,7 +124,7 @@ public class SvnModifyCommandTest extends AbstractSvnCommandTestBase { svnModifyCommand.execute(request); - WorkingCopy workingCopy = workDirFactory.createWorkingCopy(context, null); + WorkingCopy workingCopy = workingCopyFactory.createWorkingCopy(context, null); assertThat(new File(workingCopy.getWorkingRepository(), "a.txt")).exists(); assertThat(new File(workingCopy.getWorkingRepository(), "a.txt")).hasContent(""); } diff --git a/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/ApplicationModuleProvider.java b/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/ApplicationModuleProvider.java index b34610f8ce..08781b0070 100644 --- a/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/ApplicationModuleProvider.java +++ b/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/ApplicationModuleProvider.java @@ -77,7 +77,7 @@ public class ApplicationModuleProvider implements ModuleProvider { } moduleList.add(new MapperModule()); moduleList.add(new ExecutorModule()); - moduleList.add(new WorkdirModule(pluginLoader)); + moduleList.add(new WorkingCopyPoolModule(pluginLoader)); return moduleList; } diff --git a/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/WorkdirModule.java b/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/WorkingCopyPoolModule.java similarity index 63% rename from scm-webapp/src/main/java/sonia/scm/lifecycle/modules/WorkdirModule.java rename to scm-webapp/src/main/java/sonia/scm/lifecycle/modules/WorkingCopyPoolModule.java index 1f7e72ee9c..9ab838856c 100644 --- a/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/WorkdirModule.java +++ b/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/WorkingCopyPoolModule.java @@ -26,25 +26,25 @@ package sonia.scm.lifecycle.modules; import com.google.inject.AbstractModule; import sonia.scm.plugin.PluginLoader; -import sonia.scm.repository.util.CacheSupportingWorkdirProvider; +import sonia.scm.repository.util.WorkingCopyPool; -public class WorkdirModule extends AbstractModule { - public static final String DEFAULT_WORKDIR_CACHE_STRATEGY = "sonia.scm.repository.util.NoneCachingWorkdirProvider"; - public static final String WORKDIR_CACHE_STRATEGY_PROPERTY = "scm.workdirCacheStrategy"; +public class WorkingCopyPoolModule extends AbstractModule { + public static final String DEFAULT_WORKING_COPY_POOL_STRATEGY = "sonia.scm.repository.util.NoneCachingWorkingCopyPool"; + public static final String WORKING_COPY_POOL_STRATEGY_PROPERTY = "scm.workingCopyPoolStrategy"; private final PluginLoader pluginLoader; - public WorkdirModule(PluginLoader pluginLoader) { + public WorkingCopyPoolModule(PluginLoader pluginLoader) { this.pluginLoader = pluginLoader; } @Override protected void configure() { + String workingCopyPoolStrategy = System.getProperty(WORKING_COPY_POOL_STRATEGY_PROPERTY, DEFAULT_WORKING_COPY_POOL_STRATEGY); try { - String workdirCacheStrategy = System.getProperty(WORKDIR_CACHE_STRATEGY_PROPERTY, DEFAULT_WORKDIR_CACHE_STRATEGY); - Class strategyClass = (Class) pluginLoader.getUberClassLoader().loadClass(workdirCacheStrategy); - bind(CacheSupportingWorkdirProvider.class).to(strategyClass); + Class strategyClass = (Class) pluginLoader.getUberClassLoader().loadClass(workingCopyPoolStrategy); + bind(WorkingCopyPool.class).to(strategyClass); } catch (Exception e) { - throw new RuntimeException(e); + throw new RuntimeException("could not instantiate class for working copy pool: " + workingCopyPoolStrategy, e); } } } From fcdd2243c323cc18fda149b5aa3bf32734228dad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Tue, 5 May 2020 21:34:44 +0200 Subject: [PATCH 10/29] Cleanup --- .../util/SimpleWorkingCopyFactory.java | 19 +------------------ .../repository/util/WorkingCopyFactory.java | 2 ++ .../spi/SimpleSvnWorkingCopyFactoryTest.java | 2 +- 3 files changed, 4 insertions(+), 19 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/repository/util/SimpleWorkingCopyFactory.java b/scm-core/src/main/java/sonia/scm/repository/util/SimpleWorkingCopyFactory.java index 963300d84a..4a1c69a8bb 100644 --- a/scm-core/src/main/java/sonia/scm/repository/util/SimpleWorkingCopyFactory.java +++ b/scm-core/src/main/java/sonia/scm/repository/util/SimpleWorkingCopyFactory.java @@ -35,7 +35,6 @@ import javax.servlet.ServletContextListener; import java.io.File; import java.io.IOException; -@Extension public abstract class SimpleWorkingCopyFactory implements WorkingCopyFactory, ServletContextListener { private static final Logger LOG = LoggerFactory.getLogger(SimpleWorkingCopyFactory.class); @@ -76,7 +75,7 @@ public abstract class SimpleWorkingCopyFactory implements WorkingCopyFa LOG.warn("could not close central repository for {}", workingCopyContext.getScmRepository(), e); } try { - closeWorkingCopy(parentAndClone.getClone()); + closeWorkingCopyInternal(parentAndClone.getClone()); } catch (Exception e) { LOG.warn("could not close clone for {} in directory {}", workingCopyContext.getScmRepository(), parentAndClone.getDirectory(), e); } @@ -120,22 +119,6 @@ public abstract class SimpleWorkingCopyFactory implements WorkingCopyFa protected abstract ParentAndClone reclaimRepository(C context, File target, String initialBranch) throws IOException, ReclaimFailedException; - private void closeCentral(R repository) { - try { - closeRepository(repository); - } catch (Exception e) { - LOG.warn("could not close temporary repository clone", e); - } - } - - private void closeWorkingCopy(W repository) { - try { - closeWorkingCopyInternal(repository); - } catch (Exception e) { - LOG.warn("could not close temporary repository clone", e); - } - } - protected static class ParentAndClone { private final R parent; private final W clone; diff --git a/scm-core/src/main/java/sonia/scm/repository/util/WorkingCopyFactory.java b/scm-core/src/main/java/sonia/scm/repository/util/WorkingCopyFactory.java index bc48edfceb..ac0bd5fa89 100644 --- a/scm-core/src/main/java/sonia/scm/repository/util/WorkingCopyFactory.java +++ b/scm-core/src/main/java/sonia/scm/repository/util/WorkingCopyFactory.java @@ -24,6 +24,8 @@ package sonia.scm.repository.util; +import sonia.scm.plugin.ExtensionPoint; + public interface WorkingCopyFactory { WorkingCopy createWorkingCopy(C repositoryContext, String initialBranch); } diff --git a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactoryTest.java b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactoryTest.java index 5be444aed0..120f7cc20b 100644 --- a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactoryTest.java +++ b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactoryTest.java @@ -65,7 +65,7 @@ public class SimpleSvnWorkingCopyFactoryTest extends AbstractSvnCommandTestBase } @Test - public void cloneFromPoolshouldNotBeReused() { + public void cloneFromPoolShouldNotBeReused() { SimpleSvnWorkingCopyFactory factory = new SimpleSvnWorkingCopyFactory(new NoneCachingWorkingCopyPool(workdirProvider)); File firstDirectory; From e8247cbfe140b7e002043fde91e24c3b5900f7ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Thu, 7 May 2020 22:01:30 +0200 Subject: [PATCH 11/29] Clean up hg repo on reclaim --- .../spi/SimpleHgWorkingCopyFactory.java | 22 ++- .../spi/SimpleHgWorkingCopyFactoryTest.java | 150 ++++++++++++++++++ 2 files changed, 168 insertions(+), 4 deletions(-) create mode 100644 scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactoryTest.java diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactory.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactory.java index d84e6e163c..63c3769b50 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactory.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactory.java @@ -27,11 +27,14 @@ 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.ExecutionException; import com.aragost.javahg.commands.PullCommand; +import com.aragost.javahg.commands.StatusCommand; import com.aragost.javahg.commands.UpdateCommand; import com.aragost.javahg.commands.flags.CloneCommandFlags; import sonia.scm.repository.util.WorkingCopyPool; import sonia.scm.repository.util.SimpleWorkingCopyFactory; +import sonia.scm.util.IOUtil; import sonia.scm.web.HgRepositoryEnvironmentBuilder; import javax.inject.Inject; @@ -71,11 +74,22 @@ public class SimpleHgWorkingCopyFactory extends SimpleWorkingCopyFactory reclaimRepository(HgCommandContext context, File target, String initialBranch) throws IOException { + protected ParentAndClone reclaimRepository(HgCommandContext context, File target, String initialBranch) throws ReclaimFailedException { Repository centralRepository = openCentral(context); - BaseRepository clone = Repository.open(target); - UpdateCommand.on(clone).rev(initialBranch).execute(); - return new ParentAndClone<>(centralRepository, clone, target); + try { + BaseRepository clone = Repository.open(target); + for (String unknown : StatusCommand.on(clone).execute().getUnknown()) { + delete(clone.getDirectory(), unknown); + } + UpdateCommand.on(clone).rev(initialBranch).clean().execute(); + return new ParentAndClone<>(centralRepository, clone, target); + } catch (ExecutionException | IOException e) { + throw new ReclaimFailedException(e); + } + } + + private void delete(File directory, String unknownFile) throws IOException { + IOUtil.delete(new File(directory, unknownFile)); } @Override diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactoryTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactoryTest.java new file mode 100644 index 0000000000..1a3de5cf58 --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactoryTest.java @@ -0,0 +1,150 @@ +/* + * 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.repository.spi; + +import com.aragost.javahg.Repository; +import com.google.inject.util.Providers; +import org.assertj.core.api.Assertions; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.rules.TemporaryFolder; +import org.junitpioneer.jupiter.TempDirectory; +import sonia.scm.repository.HgHookManager; +import sonia.scm.repository.HgTestUtil; +import sonia.scm.repository.util.CachingAllWorkingCopyPool; +import sonia.scm.repository.util.NoneCachingWorkingCopyPool; +import sonia.scm.repository.util.WorkdirProvider; +import sonia.scm.repository.util.WorkingCopy; +import sonia.scm.web.HgRepositoryEnvironmentBuilder; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collections; + +import static org.assertj.core.api.Assertions.assertThat; + +@ExtendWith(TempDirectory.class) +public class SimpleHgWorkingCopyFactoryTest extends AbstractHgCommandTestBase { + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + private WorkdirProvider workdirProvider; + + private SimpleHgWorkingCopyFactory workingCopyFactory; + + @Before + public void bindScmProtocol() throws IOException { + workdirProvider = new WorkdirProvider(temporaryFolder.newFolder()); + HgHookManager hookManager = HgTestUtil.createHookManager(); + HgRepositoryEnvironmentBuilder environmentBuilder = new HgRepositoryEnvironmentBuilder(handler, hookManager); + workingCopyFactory = new SimpleHgWorkingCopyFactory(Providers.of(environmentBuilder), new CachingAllWorkingCopyPool(workdirProvider)) { + @Override + public void configure(com.aragost.javahg.commands.PullCommand pullCommand) { + // we do not want to configure http hooks in this unit test + } + }; + } + + @Test + public void shouldSwitchBranch() { + WorkingCopy workingCopy = workingCopyFactory.createWorkingCopy(cmdContext, "default"); + + File initialDirectory = workingCopy.getDirectory(); + workingCopy.close(); + + assertThat(initialDirectory).exists(); + assertThat(initialDirectory.toPath().resolve("f.txt")).exists(); + + WorkingCopy cachedWorkingCopy = workingCopyFactory.createWorkingCopy(cmdContext, "test-branch"); + assertThat(cachedWorkingCopy.getDirectory()).isEqualTo(initialDirectory); + assertThat(cachedWorkingCopy.getDirectory().toPath().resolve("f.txt")).doesNotExist(); + } + + @Test + public void shouldReplaceFileWithContentFromNewBranch() throws IOException { + WorkingCopy workingCopy = workingCopyFactory.createWorkingCopy(cmdContext, "test-branch"); + + File initialDirectory = workingCopy.getDirectory(); + Path fileToBeReplaced = initialDirectory.toPath().resolve("f.txt"); + Files.createFile(fileToBeReplaced); + Files.write(fileToBeReplaced, Collections.singleton("some content")); + + workingCopy.close(); + + assertThat(initialDirectory).exists(); + assertThat(fileToBeReplaced).hasContent("some content"); + + WorkingCopy cachedWorkingCopy = workingCopyFactory.createWorkingCopy(cmdContext, "default"); + assertThat(cachedWorkingCopy.getDirectory()).isEqualTo(initialDirectory); + assertThat(cachedWorkingCopy.getDirectory().toPath().resolve("f.txt")).exists(); + assertThat(fileToBeReplaced).hasContent("f"); + } + + @Test + public void shouldDeleteUntrackedFile() throws IOException { + WorkingCopy workingCopy = workingCopyFactory.createWorkingCopy(cmdContext, "test-branch"); + + File initialDirectory = workingCopy.getDirectory(); + Path fileToBeDeleted = initialDirectory.toPath().resolve("x.txt"); + Files.createFile(fileToBeDeleted); + Files.write(fileToBeDeleted, Collections.singleton("some content")); + + workingCopy.close(); + + assertThat(initialDirectory).exists(); + assertThat(fileToBeDeleted).hasContent("some content"); + + WorkingCopy cachedWorkingCopy = workingCopyFactory.createWorkingCopy(cmdContext, "default"); + assertThat(cachedWorkingCopy.getDirectory()).isEqualTo(initialDirectory); + assertThat(cachedWorkingCopy.getDirectory().toPath().resolve("x.txt")).doesNotExist(); + } + + @Test + public void shouldDeleteUntrackedDirectory() throws IOException { + WorkingCopy workingCopy = workingCopyFactory.createWorkingCopy(cmdContext, "test-branch"); + + File initialDirectory = workingCopy.getDirectory(); + Path directoryToBeDeleted = initialDirectory.toPath().resolve("newDir"); + Files.createDirectories(directoryToBeDeleted); + Path fileToBeDeleted = directoryToBeDeleted.resolve("y.txt"); + Files.createFile(fileToBeDeleted); + Files.write(fileToBeDeleted, Collections.singleton("some content")); + + workingCopy.close(); + + assertThat(initialDirectory).exists(); + assertThat(fileToBeDeleted).hasContent("some content"); + + WorkingCopy cachedWorkingCopy = workingCopyFactory.createWorkingCopy(cmdContext, "default"); + assertThat(cachedWorkingCopy.getDirectory()).isEqualTo(initialDirectory); + assertThat(cachedWorkingCopy.getDirectory().toPath().resolve("newDir")).doesNotExist(); + } +} From 1163ce90026ad1de095c7048aa33d199f1b25041 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Fri, 8 May 2020 07:40:14 +0200 Subject: [PATCH 12/29] For the time being we are happy to delete files, not directories --- .../scm/repository/spi/SimpleHgWorkingCopyFactoryTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactoryTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactoryTest.java index 1a3de5cf58..0c1edcbe9f 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactoryTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactoryTest.java @@ -145,6 +145,6 @@ public class SimpleHgWorkingCopyFactoryTest extends AbstractHgCommandTestBase { WorkingCopy cachedWorkingCopy = workingCopyFactory.createWorkingCopy(cmdContext, "default"); assertThat(cachedWorkingCopy.getDirectory()).isEqualTo(initialDirectory); - assertThat(cachedWorkingCopy.getDirectory().toPath().resolve("newDir")).doesNotExist(); + assertThat(cachedWorkingCopy.getDirectory().toPath().resolve("newDir")).isEmptyDirectory(); } } From e968aa17ef6bfcf294b00571f9845a5edb644069 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Fri, 8 May 2020 18:11:27 +0200 Subject: [PATCH 13/29] Cleanup --- .../util/CachingAllWorkingCopyPool.java | 16 +++--- .../util/NoneCachingWorkingCopyPool.java | 7 ++- .../util/SimpleWorkingCopyFactory.java | 53 ++++++------------- .../util/WorkingCopyFailedException.java | 39 ++++++++++++++ .../scm/repository/util/WorkingCopyPool.java | 28 +++++++++- .../util/CachingAllWorkingCopyPoolTest.java | 23 ++++---- .../util/SimpleWorkingCopyFactoryTest.java | 12 ++--- .../spi/SimpleGitWorkingCopyFactory.java | 15 ++++-- .../spi/SimpleHgWorkingCopyFactory.java | 10 +++- .../spi/SimpleHgWorkingCopyFactoryTest.java | 4 -- .../spi/SimpleSvnWorkingCopyFactory.java | 1 + 11 files changed, 131 insertions(+), 77 deletions(-) create mode 100644 scm-core/src/main/java/sonia/scm/repository/util/WorkingCopyFailedException.java diff --git a/scm-core/src/main/java/sonia/scm/repository/util/CachingAllWorkingCopyPool.java b/scm-core/src/main/java/sonia/scm/repository/util/CachingAllWorkingCopyPool.java index 76e3c0b9b0..612701bdc5 100644 --- a/scm-core/src/main/java/sonia/scm/repository/util/CachingAllWorkingCopyPool.java +++ b/scm-core/src/main/java/sonia/scm/repository/util/CachingAllWorkingCopyPool.java @@ -27,11 +27,11 @@ package sonia.scm.repository.util; import com.google.common.base.Stopwatch; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import sonia.scm.repository.InternalRepositoryException; import sonia.scm.util.IOUtil; import javax.inject.Inject; import java.io.File; -import java.io.IOException; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -49,13 +49,13 @@ public class CachingAllWorkingCopyPool implements WorkingCopyPool { } @Override - public SimpleWorkingCopyFactory.ParentAndClone getWorkingCopy(WorkingCopyContext workingCopyContext) throws IOException { + public ParentAndClone getWorkingCopy(WorkingCopyContext workingCopyContext) { String id = workingCopyContext.getScmRepository().getId(); File existingWorkdir = workdirs.remove(id); if (existingWorkdir != null) { Stopwatch stopwatch = Stopwatch.createStarted(); try { - SimpleWorkingCopyFactory.ParentAndClone reclaimed = workingCopyContext.getReclaimer().reclaim(existingWorkdir); + ParentAndClone reclaimed = workingCopyContext.getReclaimer().reclaim(existingWorkdir); LOG.debug("reclaimed workdir for {} in path {} in {}", workingCopyContext.getScmRepository().getNamespaceAndName(), existingWorkdir, stopwatch.stop()); return reclaimed; } catch (SimpleWorkingCopyFactory.ReclaimFailedException e) { @@ -63,13 +63,17 @@ public class CachingAllWorkingCopyPool implements WorkingCopyPool { deleteWorkdir(existingWorkdir); } } - return createNewWorkdir(workingCopyContext); + try { + return createNewWorkdir(workingCopyContext); + } catch (WorkingCopyFailedException e) { + throw new InternalRepositoryException(workingCopyContext.getScmRepository(), "failed to create working copy", e); + } } - private SimpleWorkingCopyFactory.ParentAndClone createNewWorkdir(WorkingCopyContext workingCopyContext) throws IOException { + private ParentAndClone createNewWorkdir(WorkingCopyContext workingCopyContext) throws WorkingCopyFailedException { Stopwatch stopwatch = Stopwatch.createStarted(); File newWorkdir = workdirProvider.createNewWorkdir(); - SimpleWorkingCopyFactory.ParentAndClone parentAndClone = workingCopyContext.getInitializer().initialize(newWorkdir); + ParentAndClone parentAndClone = workingCopyContext.getInitializer().initialize(newWorkdir); LOG.debug("initialized new workdir for {} in path {} in {}", workingCopyContext.getScmRepository().getNamespaceAndName(), newWorkdir, stopwatch.stop()); return parentAndClone; } diff --git a/scm-core/src/main/java/sonia/scm/repository/util/NoneCachingWorkingCopyPool.java b/scm-core/src/main/java/sonia/scm/repository/util/NoneCachingWorkingCopyPool.java index a00ee5d3eb..5a5d40bf44 100644 --- a/scm-core/src/main/java/sonia/scm/repository/util/NoneCachingWorkingCopyPool.java +++ b/scm-core/src/main/java/sonia/scm/repository/util/NoneCachingWorkingCopyPool.java @@ -28,7 +28,6 @@ import sonia.scm.util.IOUtil; import javax.inject.Inject; import java.io.File; -import java.io.IOException; public class NoneCachingWorkingCopyPool implements WorkingCopyPool { @@ -40,13 +39,13 @@ public class NoneCachingWorkingCopyPool implements WorkingCopyPool { } @Override - public SimpleWorkingCopyFactory.ParentAndClone getWorkingCopy(WorkingCopyContext context) throws IOException { + public ParentAndClone getWorkingCopy(WorkingCopyContext context) throws WorkingCopyFailedException { return context.getInitializer().initialize(workdirProvider.createNewWorkdir()); } @Override - public void contextClosed(WorkingCopyContext workingCopyContext, File workdir) throws IOException { - IOUtil.delete(workdir, true); + public void contextClosed(WorkingCopyContext workingCopyContext, File workdir) { + IOUtil.deleteSilently(workdir); } @Override diff --git a/scm-core/src/main/java/sonia/scm/repository/util/SimpleWorkingCopyFactory.java b/scm-core/src/main/java/sonia/scm/repository/util/SimpleWorkingCopyFactory.java index 4a1c69a8bb..7bcf7514b0 100644 --- a/scm-core/src/main/java/sonia/scm/repository/util/SimpleWorkingCopyFactory.java +++ b/scm-core/src/main/java/sonia/scm/repository/util/SimpleWorkingCopyFactory.java @@ -26,14 +26,12 @@ package sonia.scm.repository.util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import sonia.scm.plugin.Extension; import sonia.scm.repository.InternalRepositoryException; import sonia.scm.repository.Repository; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import java.io.File; -import java.io.IOException; public abstract class SimpleWorkingCopyFactory implements WorkingCopyFactory, ServletContextListener { @@ -49,16 +47,14 @@ public abstract class SimpleWorkingCopyFactory implements WorkingCopyFa public WorkingCopy createWorkingCopy(C repositoryContext, String initialBranch) { try { WorkingCopyContext workingCopyContext = createWorkingCopyContext(repositoryContext, initialBranch); - ParentAndClone parentAndClone = workingCopyPool.getWorkingCopy(workingCopyContext); + WorkingCopyPool.ParentAndClone parentAndClone = workingCopyPool.getWorkingCopy(workingCopyContext); return new WorkingCopy<>(parentAndClone.getClone(), parentAndClone.getParent(), () -> this.close(workingCopyContext, parentAndClone), parentAndClone.getDirectory()); - } catch (RuntimeException e) { - throw e; - } catch (Exception e) { - throw new InternalRepositoryException(getScmRepository(repositoryContext), "could not clone repository in temporary directory", e); + } catch (WorkingCopyFailedException e) { + throw new InternalRepositoryException(getScmRepository(repositoryContext), "could not create working copy for repository in temporary directory", e); } } - public WorkingCopyContext createWorkingCopyContext(C repositoryContext, String initialBranch) { + private WorkingCopyContext createWorkingCopyContext(C repositoryContext, String initialBranch) { return new WorkingCopyContext<>( getScmRepository(repositoryContext), initialBranch, @@ -68,7 +64,7 @@ public abstract class SimpleWorkingCopyFactory implements WorkingCopyFa ); } - private void close(WorkingCopyContext workingCopyContext, ParentAndClone parentAndClone) { + private void close(WorkingCopyContext workingCopyContext, WorkingCopyPool.ParentAndClone parentAndClone) { try { closeRepository(parentAndClone.getParent()); } catch (Exception e) { @@ -98,12 +94,12 @@ public abstract class SimpleWorkingCopyFactory implements WorkingCopyFa @FunctionalInterface public interface WorkingCopyInitializer { - ParentAndClone initialize(File target) throws IOException; + WorkingCopyPool.ParentAndClone initialize(File target) throws WorkingCopyFailedException; } @FunctionalInterface public interface WorkingCopyReclaimer { - ParentAndClone reclaim(File target) throws IOException, ReclaimFailedException; + WorkingCopyPool.ParentAndClone reclaim(File target) throws ReclaimFailedException; } protected abstract Repository getScmRepository(C context); @@ -115,40 +111,21 @@ public abstract class SimpleWorkingCopyFactory implements WorkingCopyFa // We do allow implementations to throw arbitrary exceptions here, so that we can handle them in closeWorkingCopy protected abstract void closeWorkingCopyInternal(W workingCopy) throws Exception; - protected abstract ParentAndClone cloneRepository(C context, File target, String initialBranch) throws IOException; + protected abstract WorkingCopyPool.ParentAndClone cloneRepository(C context, File target, String initialBranch) throws WorkingCopyFailedException; - protected abstract ParentAndClone reclaimRepository(C context, File target, String initialBranch) throws IOException, ReclaimFailedException; - - protected static class ParentAndClone { - private final R parent; - private final W clone; - private final File directory; - - public ParentAndClone(R parent, W clone, File directory) { - this.parent = parent; - this.clone = clone; - this.directory = directory; - } - - public R getParent() { - return parent; - } - - public W getClone() { - return clone; - } - - public File getDirectory() { - return directory; - } - } + protected abstract WorkingCopyPool.ParentAndClone reclaimRepository(C context, File target, String initialBranch) throws ReclaimFailedException; public static class ReclaimFailedException extends Exception { - public ReclaimFailedException() { + public ReclaimFailedException(String message) { + super(message); } public ReclaimFailedException(Throwable cause) { super(cause); } + + public ReclaimFailedException(String message, Throwable cause) { + super(message, cause); + } } } diff --git a/scm-core/src/main/java/sonia/scm/repository/util/WorkingCopyFailedException.java b/scm-core/src/main/java/sonia/scm/repository/util/WorkingCopyFailedException.java new file mode 100644 index 0000000000..943fc4c495 --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/repository/util/WorkingCopyFailedException.java @@ -0,0 +1,39 @@ +/* + * 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.repository.util; + +public class WorkingCopyFailedException extends Exception { + public WorkingCopyFailedException(String message) { + super(message); + } + + public WorkingCopyFailedException(Throwable cause) { + super(cause); + } + + public WorkingCopyFailedException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/scm-core/src/main/java/sonia/scm/repository/util/WorkingCopyPool.java b/scm-core/src/main/java/sonia/scm/repository/util/WorkingCopyPool.java index 92bc081bb4..e54deb729c 100644 --- a/scm-core/src/main/java/sonia/scm/repository/util/WorkingCopyPool.java +++ b/scm-core/src/main/java/sonia/scm/repository/util/WorkingCopyPool.java @@ -27,9 +27,33 @@ package sonia.scm.repository.util; import java.io.File; public interface WorkingCopyPool { - SimpleWorkingCopyFactory.ParentAndClone getWorkingCopy(WorkingCopyContext context) throws Exception; + ParentAndClone getWorkingCopy(WorkingCopyContext context) throws WorkingCopyFailedException; - void contextClosed(WorkingCopyContext workingCopyContext, File workdir) throws Exception; + void contextClosed(WorkingCopyContext workingCopyContext, File workdir); void shutdown(); + + class ParentAndClone { + private final R parent; + private final W clone; + private final File directory; + + public ParentAndClone(R parent, W clone, File directory) { + this.parent = parent; + this.clone = clone; + this.directory = directory; + } + + public R getParent() { + return parent; + } + + public W getClone() { + return clone; + } + + public File getDirectory() { + return directory; + } + } } diff --git a/scm-core/src/test/java/sonia/scm/repository/util/CachingAllWorkingCopyPoolTest.java b/scm-core/src/test/java/sonia/scm/repository/util/CachingAllWorkingCopyPoolTest.java index b5e011964c..6982b7c8d2 100644 --- a/scm-core/src/test/java/sonia/scm/repository/util/CachingAllWorkingCopyPoolTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/util/CachingAllWorkingCopyPoolTest.java @@ -34,7 +34,6 @@ import org.mockito.junit.jupiter.MockitoExtension; import sonia.scm.repository.Repository; import java.io.File; -import java.io.IOException; import java.nio.file.Path; import static org.assertj.core.api.Assertions.assertThat; @@ -62,34 +61,34 @@ class CachingAllWorkingCopyPoolTest { SimpleWorkingCopyFactory.WorkingCopyReclaimer reclaimer; @BeforeEach - void initContext() throws IOException, SimpleWorkingCopyFactory.ReclaimFailedException { + void initContext() throws SimpleWorkingCopyFactory.ReclaimFailedException, WorkingCopyFailedException { lenient().when(workingCopyContext.getInitializer()).thenReturn(initializer); lenient().when(workingCopyContext.getReclaimer()).thenReturn(reclaimer); lenient().when(initializer.initialize(any())) - .thenAnswer(invocationOnMock -> new SimpleWorkingCopyFactory.ParentAndClone<>(null, null, invocationOnMock.getArgument(0, File.class))); + .thenAnswer(invocationOnMock -> new WorkingCopyPool.ParentAndClone<>(null, null, invocationOnMock.getArgument(0, File.class))); lenient().when(reclaimer.reclaim(any())) - .thenAnswer(invocationOnMock -> new SimpleWorkingCopyFactory.ParentAndClone<>(null, null, invocationOnMock.getArgument(0, File.class))); + .thenAnswer(invocationOnMock -> new WorkingCopyPool.ParentAndClone<>(null, null, invocationOnMock.getArgument(0, File.class))); } @Test - void shouldCreateNewWorkdirForTheFirstRequest(@TempDir Path temp) throws IOException { + void shouldCreateNewWorkdirForTheFirstRequest(@TempDir Path temp) throws WorkingCopyFailedException { when(workingCopyContext.getScmRepository()).thenReturn(REPOSITORY); when(workdirProvider.createNewWorkdir()).thenReturn(temp.toFile()); - SimpleWorkingCopyFactory.ParentAndClone workdir = cachingAllWorkingCopyPool.getWorkingCopy(workingCopyContext); + WorkingCopyPool.ParentAndClone workdir = cachingAllWorkingCopyPool.getWorkingCopy(workingCopyContext); verify(initializer).initialize(temp.toFile()); } @Test - void shouldCreateWorkdirOnlyOnceForTheSameRepository(@TempDir Path temp) throws IOException, SimpleWorkingCopyFactory.ReclaimFailedException { + void shouldCreateWorkdirOnlyOnceForTheSameRepository(@TempDir Path temp) throws SimpleWorkingCopyFactory.ReclaimFailedException, WorkingCopyFailedException { when(workingCopyContext.getScmRepository()).thenReturn(REPOSITORY); when(workdirProvider.createNewWorkdir()).thenReturn(temp.toFile()); - SimpleWorkingCopyFactory.ParentAndClone firstWorkdir = cachingAllWorkingCopyPool.getWorkingCopy(workingCopyContext); + WorkingCopyPool.ParentAndClone firstWorkdir = cachingAllWorkingCopyPool.getWorkingCopy(workingCopyContext); cachingAllWorkingCopyPool.contextClosed(workingCopyContext, firstWorkdir.getDirectory()); - SimpleWorkingCopyFactory.ParentAndClone secondWorkdir = cachingAllWorkingCopyPool.getWorkingCopy(workingCopyContext); + WorkingCopyPool.ParentAndClone secondWorkdir = cachingAllWorkingCopyPool.getWorkingCopy(workingCopyContext); verify(initializer).initialize(temp.toFile()); verify(reclaimer).reclaim(temp.toFile()); @@ -97,7 +96,7 @@ class CachingAllWorkingCopyPoolTest { } @Test - void shouldCacheOnlyOneWorkdirForRepository(@TempDir Path temp) throws IOException, SimpleWorkingCopyFactory.ReclaimFailedException { + void shouldCacheOnlyOneWorkdirForRepository(@TempDir Path temp) throws SimpleWorkingCopyFactory.ReclaimFailedException, WorkingCopyFailedException { when(workingCopyContext.getScmRepository()).thenReturn(REPOSITORY); File firstDirectory = temp.resolve("first").toFile(); firstDirectory.mkdirs(); @@ -107,8 +106,8 @@ class CachingAllWorkingCopyPoolTest { firstDirectory, secondDirectory); - SimpleWorkingCopyFactory.ParentAndClone firstWorkdir = cachingAllWorkingCopyPool.getWorkingCopy(workingCopyContext); - SimpleWorkingCopyFactory.ParentAndClone secondWorkdir = cachingAllWorkingCopyPool.getWorkingCopy(workingCopyContext); + WorkingCopyPool.ParentAndClone firstWorkdir = cachingAllWorkingCopyPool.getWorkingCopy(workingCopyContext); + WorkingCopyPool.ParentAndClone secondWorkdir = cachingAllWorkingCopyPool.getWorkingCopy(workingCopyContext); cachingAllWorkingCopyPool.contextClosed(workingCopyContext, firstWorkdir.getDirectory()); cachingAllWorkingCopyPool.contextClosed(workingCopyContext, secondWorkdir.getDirectory()); diff --git a/scm-core/src/test/java/sonia/scm/repository/util/SimpleWorkingCopyFactoryTest.java b/scm-core/src/test/java/sonia/scm/repository/util/SimpleWorkingCopyFactoryTest.java index 87e80d65bd..97364e12ec 100644 --- a/scm-core/src/test/java/sonia/scm/repository/util/SimpleWorkingCopyFactoryTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/util/SimpleWorkingCopyFactoryTest.java @@ -61,15 +61,15 @@ public class SimpleWorkingCopyFactoryTest { WorkdirProvider workdirProvider = new WorkdirProvider(temporaryFolder.newFolder()); WorkingCopyPool configurableTestWorkingCopyPool = new WorkingCopyPool() { @Override - public SimpleWorkingCopyFactory.ParentAndClone getWorkingCopy(WorkingCopyContext context) throws IOException { + public ParentAndClone getWorkingCopy(WorkingCopyContext context) throws WorkingCopyFailedException { workdir = workdirProvider.createNewWorkdir(); return context.getInitializer().initialize(workdir); } @Override - public void contextClosed(WorkingCopyContext createWorkdirContext, File workdir) throws Exception { + public void contextClosed(WorkingCopyContext createWorkdirContext, File workdir) { if (!workdirIsCached) { - IOUtil.delete(workdir); + IOUtil.deleteSilently(workdir); } } @@ -89,7 +89,7 @@ public class SimpleWorkingCopyFactoryTest { } @Override - protected ParentAndClone reclaimRepository(Context context, File target, String initialBranch) throws IOException { + protected WorkingCopyPool.ParentAndClone reclaimRepository(Context context, File target, String initialBranch) { throw new UnsupportedOperationException(); } @@ -99,9 +99,9 @@ public class SimpleWorkingCopyFactoryTest { } @Override - protected ParentAndClone cloneRepository(Context context, File target, String initialBranch) { + protected WorkingCopyPool.ParentAndClone cloneRepository(Context context, File target, String initialBranch) { initialBranchForLastCloneCall = initialBranch; - return new ParentAndClone<>(parent, clone, target); + return new WorkingCopyPool.ParentAndClone<>(parent, clone, target); } }; } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactory.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactory.java index e752042d74..088eb099eb 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactory.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactory.java @@ -38,6 +38,7 @@ import sonia.scm.repository.GitWorkingCopyFactory; import sonia.scm.repository.InternalRepositoryException; import sonia.scm.repository.util.WorkingCopyPool; import sonia.scm.repository.util.SimpleWorkingCopyFactory; +import sonia.scm.repository.util.WorkingCopyPool.ParentAndClone; import sonia.scm.util.SystemUtil; import javax.inject.Inject; @@ -85,10 +86,10 @@ public class SimpleGitWorkingCopyFactory extends SimpleWorkingCopyFactory reclaimRepository(GitContext context, File target, String initialBranch) throws IOException, ReclaimFailedException { + protected ParentAndClone reclaimRepository(GitContext context, File target, String initialBranch) throws ReclaimFailedException { LOG.trace("reclaim repository {}", context.getRepository().getId()); long start = System.nanoTime(); - Repository repo = GitUtil.open(target); + Repository repo = openTarget(target); try (Git git = Git.open(target)) { git.reset().setMode(ResetCommand.ResetType.HARD).call(); git.clean().setForce(true).setCleanDirectories(true).call(); @@ -97,7 +98,7 @@ public class SimpleGitWorkingCopyFactory extends SimpleWorkingCopyFactory(null, repo, target); - } catch (GitAPIException e) { + } catch (GitAPIException | IOException e) { throw new ReclaimFailedException(e); } finally { long end = System.nanoTime(); @@ -106,6 +107,14 @@ public class SimpleGitWorkingCopyFactory extends SimpleWorkingCopyFactory cloneRepository(HgCommandContext context, File target, String initialBranch) throws IOException { + public ParentAndClone cloneRepository(HgCommandContext context, File target, String initialBranch) throws WorkingCopyFailedException { Repository centralRepository = openCentral(context); CloneCommand cloneCommand = CloneCommandFlags.on(centralRepository); if (initialBranch != null) { cloneCommand.updaterev(initialBranch); } - cloneCommand.execute(target.getAbsolutePath()); + try { + cloneCommand.execute(target.getAbsolutePath()); + } catch (IOException e) { + throw new WorkingCopyFailedException(e); + } BaseRepository clone = Repository.open(target); diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactoryTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactoryTest.java index 0c1edcbe9f..9199a23c92 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactoryTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactoryTest.java @@ -31,13 +31,10 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.junit.rules.TemporaryFolder; -import org.junitpioneer.jupiter.TempDirectory; import sonia.scm.repository.HgHookManager; import sonia.scm.repository.HgTestUtil; import sonia.scm.repository.util.CachingAllWorkingCopyPool; -import sonia.scm.repository.util.NoneCachingWorkingCopyPool; import sonia.scm.repository.util.WorkdirProvider; import sonia.scm.repository.util.WorkingCopy; import sonia.scm.web.HgRepositoryEnvironmentBuilder; @@ -50,7 +47,6 @@ import java.util.Collections; import static org.assertj.core.api.Assertions.assertThat; -@ExtendWith(TempDirectory.class) public class SimpleHgWorkingCopyFactoryTest extends AbstractHgCommandTestBase { @Rule diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactory.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactory.java index a0bfd8cd41..922eb3bc38 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactory.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactory.java @@ -37,6 +37,7 @@ import sonia.scm.repository.Repository; import sonia.scm.repository.SvnWorkingCopyFactory; import sonia.scm.repository.util.WorkingCopyPool; import sonia.scm.repository.util.SimpleWorkingCopyFactory; +import sonia.scm.repository.util.WorkingCopyPool.ParentAndClone; import javax.inject.Inject; import java.io.File; From f74b7626ebc42f8417157cc2570bd6ae8f1e907e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Fri, 8 May 2020 18:18:43 +0200 Subject: [PATCH 14/29] New package for working copy related classes --- .../repository/api/ModifyCommandBuilder.java | 4 +- .../scm/repository/api/RepositoryService.java | 4 +- .../api/RepositoryServiceFactory.java | 2 +- .../scm/repository/util/CloseableWrapper.java | 45 --------------- .../CachingAllWorkingCopyPool.java | 2 +- .../NoneCachingWorkingCopyPool.java | 2 +- .../SimpleWorkingCopyFactory.java | 2 +- .../{util => work}/WorkdirProvider.java | 2 +- .../{util => work}/WorkingCopy.java | 2 +- .../{util => work}/WorkingCopyContext.java | 2 +- .../{util => work}/WorkingCopyFactory.java | 4 +- .../WorkingCopyFailedException.java | 2 +- .../{util => work}/WorkingCopyPool.java | 2 +- .../api/ModifyCommandBuilderTest.java | 2 +- .../api/RepositoryServiceFactoryTest.java | 6 +- .../CachingAllWorkingCopyPoolTest.java | 2 +- .../SimpleWorkingCopyFactoryTest.java | 3 +- .../scm/repository/GitWorkingCopyFactory.java | 2 +- .../repository/spi/AbstractGitCommand.java | 2 +- .../spi/SimpleGitWorkingCopyFactory.java | 6 +- .../scm/repository/CloseableWrapperTest.java | 55 ------------------- .../repository/spi/GitMergeCommandTest.java | 4 +- .../spi/GitMergeCommand_Conflict_Test.java | 4 +- .../repository/spi/GitModifyCommandTest.java | 4 +- .../spi/GitModifyCommand_LFSTest.java | 4 +- ...ModifyCommand_withEmptyRepositoryTest.java | 4 +- .../spi/SimpleGitWorkingCopyFactoryTest.java | 6 +- .../scm/repository/spi/HgBranchCommand.java | 2 +- .../scm/repository/spi/HgModifyCommand.java | 2 +- .../repository/spi/HgWorkingCopyFactory.java | 2 +- .../spi/SimpleHgWorkingCopyFactory.java | 8 +-- .../repository/spi/HgBranchCommandTest.java | 4 +- .../repository/spi/HgModifyCommandTest.java | 4 +- .../spi/SimpleHgWorkingCopyFactoryTest.java | 8 +-- .../scm/repository/SvnWorkingCopyFactory.java | 2 +- .../spi/SimpleSvnWorkingCopyFactory.java | 6 +- .../scm/repository/spi/SvnModifyCommand.java | 2 +- .../spi/SimpleSvnWorkingCopyFactoryTest.java | 6 +- .../repository/spi/SvnModifyCommandTest.java | 6 +- .../modules/WorkingCopyPoolModule.java | 4 +- 40 files changed, 66 insertions(+), 169 deletions(-) delete mode 100644 scm-core/src/main/java/sonia/scm/repository/util/CloseableWrapper.java rename scm-core/src/main/java/sonia/scm/repository/{util => work}/CachingAllWorkingCopyPool.java (99%) rename scm-core/src/main/java/sonia/scm/repository/{util => work}/NoneCachingWorkingCopyPool.java (98%) rename scm-core/src/main/java/sonia/scm/repository/{util => work}/SimpleWorkingCopyFactory.java (99%) rename scm-core/src/main/java/sonia/scm/repository/{util => work}/WorkdirProvider.java (98%) rename scm-core/src/main/java/sonia/scm/repository/{util => work}/WorkingCopy.java (98%) rename scm-core/src/main/java/sonia/scm/repository/{util => work}/WorkingCopyContext.java (98%) rename scm-core/src/main/java/sonia/scm/repository/{util => work}/WorkingCopyFactory.java (94%) rename scm-core/src/main/java/sonia/scm/repository/{util => work}/WorkingCopyFailedException.java (97%) rename scm-core/src/main/java/sonia/scm/repository/{util => work}/WorkingCopyPool.java (98%) rename scm-core/src/test/java/sonia/scm/repository/{util => work}/CachingAllWorkingCopyPoolTest.java (99%) rename scm-core/src/test/java/sonia/scm/repository/{util => work}/SimpleWorkingCopyFactoryTest.java (99%) delete mode 100644 scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/CloseableWrapperTest.java diff --git a/scm-core/src/main/java/sonia/scm/repository/api/ModifyCommandBuilder.java b/scm-core/src/main/java/sonia/scm/repository/api/ModifyCommandBuilder.java index 57f70dcdc3..1035ccf009 100644 --- a/scm-core/src/main/java/sonia/scm/repository/api/ModifyCommandBuilder.java +++ b/scm-core/src/main/java/sonia/scm/repository/api/ModifyCommandBuilder.java @@ -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.api; import com.google.common.base.Preconditions; @@ -34,7 +34,7 @@ import sonia.scm.repository.Person; import sonia.scm.repository.spi.ModifyCommand; import sonia.scm.repository.spi.ModifyCommandRequest; import sonia.scm.repository.util.AuthorUtil; -import sonia.scm.repository.util.WorkdirProvider; +import sonia.scm.repository.work.WorkdirProvider; import sonia.scm.util.IOUtil; import java.io.File; diff --git a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java index a1978df90d..43f443b4bb 100644 --- a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java +++ b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java @@ -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.api; import org.slf4j.Logger; @@ -33,7 +33,7 @@ import sonia.scm.repository.PreProcessorUtil; import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryPermissions; import sonia.scm.repository.spi.RepositoryServiceProvider; -import sonia.scm.repository.util.WorkdirProvider; +import sonia.scm.repository.work.WorkdirProvider; import java.io.Closeable; import java.io.IOException; diff --git a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryServiceFactory.java b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryServiceFactory.java index 15bc338ff0..60b11162d1 100644 --- a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryServiceFactory.java +++ b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryServiceFactory.java @@ -53,7 +53,7 @@ import sonia.scm.repository.RepositoryManager; import sonia.scm.repository.RepositoryPermissions; import sonia.scm.repository.spi.RepositoryServiceProvider; import sonia.scm.repository.spi.RepositoryServiceResolver; -import sonia.scm.repository.util.WorkdirProvider; +import sonia.scm.repository.work.WorkdirProvider; import sonia.scm.security.ScmSecurityException; import java.util.Set; diff --git a/scm-core/src/main/java/sonia/scm/repository/util/CloseableWrapper.java b/scm-core/src/main/java/sonia/scm/repository/util/CloseableWrapper.java deleted file mode 100644 index 3015387c6a..0000000000 --- a/scm-core/src/main/java/sonia/scm/repository/util/CloseableWrapper.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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.repository.util; - -import java.util.function.Consumer; - -public class CloseableWrapper implements AutoCloseable { - - private final T wrapped; - private final Consumer cleanup; - - public CloseableWrapper(T wrapped, Consumer cleanup) { - this.wrapped = wrapped; - this.cleanup = cleanup; - } - - public T get() { return wrapped; } - - @Override - public void close() { - cleanup.accept(wrapped); - } -} diff --git a/scm-core/src/main/java/sonia/scm/repository/util/CachingAllWorkingCopyPool.java b/scm-core/src/main/java/sonia/scm/repository/work/CachingAllWorkingCopyPool.java similarity index 99% rename from scm-core/src/main/java/sonia/scm/repository/util/CachingAllWorkingCopyPool.java rename to scm-core/src/main/java/sonia/scm/repository/work/CachingAllWorkingCopyPool.java index 612701bdc5..f93a374c00 100644 --- a/scm-core/src/main/java/sonia/scm/repository/util/CachingAllWorkingCopyPool.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/CachingAllWorkingCopyPool.java @@ -22,7 +22,7 @@ * SOFTWARE. */ -package sonia.scm.repository.util; +package sonia.scm.repository.work; import com.google.common.base.Stopwatch; import org.slf4j.Logger; diff --git a/scm-core/src/main/java/sonia/scm/repository/util/NoneCachingWorkingCopyPool.java b/scm-core/src/main/java/sonia/scm/repository/work/NoneCachingWorkingCopyPool.java similarity index 98% rename from scm-core/src/main/java/sonia/scm/repository/util/NoneCachingWorkingCopyPool.java rename to scm-core/src/main/java/sonia/scm/repository/work/NoneCachingWorkingCopyPool.java index 5a5d40bf44..c5aef18b0e 100644 --- a/scm-core/src/main/java/sonia/scm/repository/util/NoneCachingWorkingCopyPool.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/NoneCachingWorkingCopyPool.java @@ -22,7 +22,7 @@ * SOFTWARE. */ -package sonia.scm.repository.util; +package sonia.scm.repository.work; import sonia.scm.util.IOUtil; diff --git a/scm-core/src/main/java/sonia/scm/repository/util/SimpleWorkingCopyFactory.java b/scm-core/src/main/java/sonia/scm/repository/work/SimpleWorkingCopyFactory.java similarity index 99% rename from scm-core/src/main/java/sonia/scm/repository/util/SimpleWorkingCopyFactory.java rename to scm-core/src/main/java/sonia/scm/repository/work/SimpleWorkingCopyFactory.java index 7bcf7514b0..76bb0a7b5e 100644 --- a/scm-core/src/main/java/sonia/scm/repository/util/SimpleWorkingCopyFactory.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/SimpleWorkingCopyFactory.java @@ -22,7 +22,7 @@ * SOFTWARE. */ -package sonia.scm.repository.util; +package sonia.scm.repository.work; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/scm-core/src/main/java/sonia/scm/repository/util/WorkdirProvider.java b/scm-core/src/main/java/sonia/scm/repository/work/WorkdirProvider.java similarity index 98% rename from scm-core/src/main/java/sonia/scm/repository/util/WorkdirProvider.java rename to scm-core/src/main/java/sonia/scm/repository/work/WorkdirProvider.java index a6acd537cc..7f511b8d74 100644 --- a/scm-core/src/main/java/sonia/scm/repository/util/WorkdirProvider.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/WorkdirProvider.java @@ -22,7 +22,7 @@ * SOFTWARE. */ -package sonia.scm.repository.util; +package sonia.scm.repository.work; import java.io.File; import java.io.IOException; diff --git a/scm-core/src/main/java/sonia/scm/repository/util/WorkingCopy.java b/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopy.java similarity index 98% rename from scm-core/src/main/java/sonia/scm/repository/util/WorkingCopy.java rename to scm-core/src/main/java/sonia/scm/repository/work/WorkingCopy.java index 8eb0cf9911..009fc4f109 100644 --- a/scm-core/src/main/java/sonia/scm/repository/util/WorkingCopy.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopy.java @@ -22,7 +22,7 @@ * SOFTWARE. */ -package sonia.scm.repository.util; +package sonia.scm.repository.work; import sonia.scm.util.IOUtil; diff --git a/scm-core/src/main/java/sonia/scm/repository/util/WorkingCopyContext.java b/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyContext.java similarity index 98% rename from scm-core/src/main/java/sonia/scm/repository/util/WorkingCopyContext.java rename to scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyContext.java index 684ee6ce21..9033a1b461 100644 --- a/scm-core/src/main/java/sonia/scm/repository/util/WorkingCopyContext.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyContext.java @@ -22,7 +22,7 @@ * SOFTWARE. */ -package sonia.scm.repository.util; +package sonia.scm.repository.work; import sonia.scm.repository.Repository; diff --git a/scm-core/src/main/java/sonia/scm/repository/util/WorkingCopyFactory.java b/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyFactory.java similarity index 94% rename from scm-core/src/main/java/sonia/scm/repository/util/WorkingCopyFactory.java rename to scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyFactory.java index ac0bd5fa89..37ea57a11a 100644 --- a/scm-core/src/main/java/sonia/scm/repository/util/WorkingCopyFactory.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyFactory.java @@ -22,9 +22,7 @@ * SOFTWARE. */ -package sonia.scm.repository.util; - -import sonia.scm.plugin.ExtensionPoint; +package sonia.scm.repository.work; public interface WorkingCopyFactory { WorkingCopy createWorkingCopy(C repositoryContext, String initialBranch); diff --git a/scm-core/src/main/java/sonia/scm/repository/util/WorkingCopyFailedException.java b/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyFailedException.java similarity index 97% rename from scm-core/src/main/java/sonia/scm/repository/util/WorkingCopyFailedException.java rename to scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyFailedException.java index 943fc4c495..985e348de7 100644 --- a/scm-core/src/main/java/sonia/scm/repository/util/WorkingCopyFailedException.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyFailedException.java @@ -22,7 +22,7 @@ * SOFTWARE. */ -package sonia.scm.repository.util; +package sonia.scm.repository.work; public class WorkingCopyFailedException extends Exception { public WorkingCopyFailedException(String message) { diff --git a/scm-core/src/main/java/sonia/scm/repository/util/WorkingCopyPool.java b/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyPool.java similarity index 98% rename from scm-core/src/main/java/sonia/scm/repository/util/WorkingCopyPool.java rename to scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyPool.java index e54deb729c..dfbaac91b9 100644 --- a/scm-core/src/main/java/sonia/scm/repository/util/WorkingCopyPool.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyPool.java @@ -22,7 +22,7 @@ * SOFTWARE. */ -package sonia.scm.repository.util; +package sonia.scm.repository.work; import java.io.File; diff --git a/scm-core/src/test/java/sonia/scm/repository/api/ModifyCommandBuilderTest.java b/scm-core/src/test/java/sonia/scm/repository/api/ModifyCommandBuilderTest.java index a374a2272c..5583261e52 100644 --- a/scm-core/src/test/java/sonia/scm/repository/api/ModifyCommandBuilderTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/api/ModifyCommandBuilderTest.java @@ -37,7 +37,7 @@ import org.mockito.stubbing.Answer; import sonia.scm.repository.Person; import sonia.scm.repository.spi.ModifyCommand; import sonia.scm.repository.spi.ModifyCommandRequest; -import sonia.scm.repository.util.WorkdirProvider; +import sonia.scm.repository.work.WorkdirProvider; import java.io.ByteArrayInputStream; import java.io.File; diff --git a/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceFactoryTest.java b/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceFactoryTest.java index d908321bb6..492d23dec8 100644 --- a/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceFactoryTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceFactoryTest.java @@ -45,11 +45,13 @@ import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryManager; import sonia.scm.repository.spi.RepositoryServiceProvider; import sonia.scm.repository.spi.RepositoryServiceResolver; -import sonia.scm.repository.util.WorkdirProvider; +import sonia.scm.repository.work.WorkdirProvider; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class RepositoryServiceFactoryTest { diff --git a/scm-core/src/test/java/sonia/scm/repository/util/CachingAllWorkingCopyPoolTest.java b/scm-core/src/test/java/sonia/scm/repository/work/CachingAllWorkingCopyPoolTest.java similarity index 99% rename from scm-core/src/test/java/sonia/scm/repository/util/CachingAllWorkingCopyPoolTest.java rename to scm-core/src/test/java/sonia/scm/repository/work/CachingAllWorkingCopyPoolTest.java index 6982b7c8d2..74ccbe029b 100644 --- a/scm-core/src/test/java/sonia/scm/repository/util/CachingAllWorkingCopyPoolTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/work/CachingAllWorkingCopyPoolTest.java @@ -22,7 +22,7 @@ * SOFTWARE. */ -package sonia.scm.repository.util; +package sonia.scm.repository.work; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/scm-core/src/test/java/sonia/scm/repository/util/SimpleWorkingCopyFactoryTest.java b/scm-core/src/test/java/sonia/scm/repository/work/SimpleWorkingCopyFactoryTest.java similarity index 99% rename from scm-core/src/test/java/sonia/scm/repository/util/SimpleWorkingCopyFactoryTest.java rename to scm-core/src/test/java/sonia/scm/repository/work/SimpleWorkingCopyFactoryTest.java index 97364e12ec..fd12e578dd 100644 --- a/scm-core/src/test/java/sonia/scm/repository/util/SimpleWorkingCopyFactoryTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/work/SimpleWorkingCopyFactoryTest.java @@ -22,8 +22,7 @@ * SOFTWARE. */ -package sonia.scm.repository.util; - +package sonia.scm.repository.work; import org.junit.Before; import org.junit.Rule; diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitWorkingCopyFactory.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitWorkingCopyFactory.java index 7585d2824f..8b127d8fde 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitWorkingCopyFactory.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitWorkingCopyFactory.java @@ -26,7 +26,7 @@ package sonia.scm.repository; import org.eclipse.jgit.lib.Repository; import sonia.scm.repository.spi.GitContext; -import sonia.scm.repository.util.WorkingCopyFactory; +import sonia.scm.repository.work.WorkingCopyFactory; public interface GitWorkingCopyFactory extends WorkingCopyFactory { } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/AbstractGitCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/AbstractGitCommand.java index 11e2040f57..d52d0a1574 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/AbstractGitCommand.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/AbstractGitCommand.java @@ -45,7 +45,7 @@ import sonia.scm.repository.GitUtil; import sonia.scm.repository.GitWorkingCopyFactory; import sonia.scm.repository.InternalRepositoryException; import sonia.scm.repository.Person; -import sonia.scm.repository.util.WorkingCopy; +import sonia.scm.repository.work.WorkingCopy; import sonia.scm.user.User; import java.io.IOException; diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactory.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactory.java index 088eb099eb..ecd874e20c 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactory.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactory.java @@ -36,9 +36,9 @@ import org.slf4j.LoggerFactory; import sonia.scm.repository.GitUtil; import sonia.scm.repository.GitWorkingCopyFactory; import sonia.scm.repository.InternalRepositoryException; -import sonia.scm.repository.util.WorkingCopyPool; -import sonia.scm.repository.util.SimpleWorkingCopyFactory; -import sonia.scm.repository.util.WorkingCopyPool.ParentAndClone; +import sonia.scm.repository.work.WorkingCopyPool; +import sonia.scm.repository.work.SimpleWorkingCopyFactory; +import sonia.scm.repository.work.WorkingCopyPool.ParentAndClone; import sonia.scm.util.SystemUtil; import javax.inject.Inject; diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/CloseableWrapperTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/CloseableWrapperTest.java deleted file mode 100644 index f1069afede..0000000000 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/CloseableWrapperTest.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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.repository; - -import org.junit.Test; -import sonia.scm.repository.util.CloseableWrapper; - -import java.util.function.Consumer; - -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; - -public class CloseableWrapperTest { - - @Test - public void shouldExecuteGivenMethodAtClose() { - Consumer wrapped = new Consumer() { - // no this cannot be replaced with a lambda because otherwise we could not use Mockito#spy - @Override - public void accept(AutoCloseable s) { - } - }; - - Consumer closer = spy(wrapped); - - AutoCloseable autoCloseable = () -> {}; - try (CloseableWrapper wrapper = new CloseableWrapper<>(autoCloseable, closer)) { - // nothing to do here - } - - verify(closer).accept(autoCloseable); - } -} diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitMergeCommandTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitMergeCommandTest.java index d8484fecb1..0bf61a739b 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitMergeCommandTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitMergeCommandTest.java @@ -44,8 +44,8 @@ import sonia.scm.repository.GitWorkingCopyFactory; import sonia.scm.repository.Person; import sonia.scm.repository.api.MergeCommandResult; import sonia.scm.repository.api.MergeStrategy; -import sonia.scm.repository.util.NoneCachingWorkingCopyPool; -import sonia.scm.repository.util.WorkdirProvider; +import sonia.scm.repository.work.NoneCachingWorkingCopyPool; +import sonia.scm.repository.work.WorkdirProvider; import sonia.scm.user.User; import java.io.BufferedWriter; diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitMergeCommand_Conflict_Test.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitMergeCommand_Conflict_Test.java index 1581e2ec08..4c1763966e 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitMergeCommand_Conflict_Test.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitMergeCommand_Conflict_Test.java @@ -27,8 +27,8 @@ package sonia.scm.repository.spi; import org.junit.Rule; import org.junit.Test; import sonia.scm.repository.spi.MergeConflictResult.SingleMergeConflict; -import sonia.scm.repository.util.NoneCachingWorkingCopyPool; -import sonia.scm.repository.util.WorkdirProvider; +import sonia.scm.repository.work.NoneCachingWorkingCopyPool; +import sonia.scm.repository.work.WorkdirProvider; import java.io.IOException; diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommandTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommandTest.java index 23799071b4..e72ad1af7e 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommandTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommandTest.java @@ -42,8 +42,8 @@ import sonia.scm.BadRequestException; import sonia.scm.ConcurrentModificationException; import sonia.scm.NotFoundException; import sonia.scm.repository.Person; -import sonia.scm.repository.util.NoneCachingWorkingCopyPool; -import sonia.scm.repository.util.WorkdirProvider; +import sonia.scm.repository.work.NoneCachingWorkingCopyPool; +import sonia.scm.repository.work.WorkdirProvider; import sonia.scm.web.lfs.LfsBlobStoreFactory; import java.io.File; diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_LFSTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_LFSTest.java index df3f2689a0..6709505c90 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_LFSTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_LFSTest.java @@ -35,8 +35,8 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import sonia.scm.repository.Person; -import sonia.scm.repository.util.NoneCachingWorkingCopyPool; -import sonia.scm.repository.util.WorkdirProvider; +import sonia.scm.repository.work.NoneCachingWorkingCopyPool; +import sonia.scm.repository.work.WorkdirProvider; import sonia.scm.store.Blob; import sonia.scm.store.BlobStore; import sonia.scm.web.lfs.LfsBlobStoreFactory; diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_withEmptyRepositoryTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_withEmptyRepositoryTest.java index bf6d255538..5898845a74 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_withEmptyRepositoryTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_withEmptyRepositoryTest.java @@ -38,8 +38,8 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import sonia.scm.repository.Person; -import sonia.scm.repository.util.NoneCachingWorkingCopyPool; -import sonia.scm.repository.util.WorkdirProvider; +import sonia.scm.repository.work.NoneCachingWorkingCopyPool; +import sonia.scm.repository.work.WorkdirProvider; import sonia.scm.web.lfs.LfsBlobStoreFactory; import java.io.File; diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactoryTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactoryTest.java index 868c96c023..0b2ba55d95 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactoryTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactoryTest.java @@ -38,9 +38,9 @@ import sonia.scm.repository.GitRepositoryHandler; import sonia.scm.repository.PreProcessorUtil; import sonia.scm.repository.RepositoryManager; import sonia.scm.repository.api.HookContextFactory; -import sonia.scm.repository.util.NoneCachingWorkingCopyPool; -import sonia.scm.repository.util.WorkdirProvider; -import sonia.scm.repository.util.WorkingCopy; +import sonia.scm.repository.work.NoneCachingWorkingCopyPool; +import sonia.scm.repository.work.WorkdirProvider; +import sonia.scm.repository.work.WorkingCopy; import java.io.File; import java.io.IOException; diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgBranchCommand.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgBranchCommand.java index 704e68343c..3a291b4501 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgBranchCommand.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgBranchCommand.java @@ -34,7 +34,7 @@ import sonia.scm.ContextEntry; import sonia.scm.repository.Branch; import sonia.scm.repository.InternalRepositoryException; import sonia.scm.repository.api.BranchRequest; -import sonia.scm.repository.util.WorkingCopy; +import sonia.scm.repository.work.WorkingCopy; import sonia.scm.user.User; /** diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgModifyCommand.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgModifyCommand.java index ea496fe74c..012592c7a4 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgModifyCommand.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgModifyCommand.java @@ -33,7 +33,7 @@ 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 sonia.scm.repository.work.WorkingCopy; import java.io.File; import java.io.IOException; diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgWorkingCopyFactory.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgWorkingCopyFactory.java index 1dfc938493..15c39aa77e 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgWorkingCopyFactory.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgWorkingCopyFactory.java @@ -26,7 +26,7 @@ package sonia.scm.repository.spi; import com.aragost.javahg.Repository; import com.aragost.javahg.commands.PullCommand; -import sonia.scm.repository.util.WorkingCopyFactory; +import sonia.scm.repository.work.WorkingCopyFactory; public interface HgWorkingCopyFactory extends WorkingCopyFactory { void configure(PullCommand pullCommand); diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactory.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactory.java index 6e35d0f9ae..9285cf3417 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactory.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactory.java @@ -32,10 +32,10 @@ import com.aragost.javahg.commands.PullCommand; import com.aragost.javahg.commands.StatusCommand; import com.aragost.javahg.commands.UpdateCommand; import com.aragost.javahg.commands.flags.CloneCommandFlags; -import sonia.scm.repository.util.WorkingCopyFailedException; -import sonia.scm.repository.util.WorkingCopyPool; -import sonia.scm.repository.util.SimpleWorkingCopyFactory; -import sonia.scm.repository.util.WorkingCopyPool.ParentAndClone; +import sonia.scm.repository.work.WorkingCopyFailedException; +import sonia.scm.repository.work.WorkingCopyPool; +import sonia.scm.repository.work.SimpleWorkingCopyFactory; +import sonia.scm.repository.work.WorkingCopyPool.ParentAndClone; import sonia.scm.util.IOUtil; import sonia.scm.web.HgRepositoryEnvironmentBuilder; diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgBranchCommandTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgBranchCommandTest.java index 11acd21f1d..0972f11e8f 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgBranchCommandTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgBranchCommandTest.java @@ -32,8 +32,8 @@ import sonia.scm.repository.Branch; import sonia.scm.repository.HgTestUtil; import sonia.scm.repository.InternalRepositoryException; import sonia.scm.repository.api.BranchRequest; -import sonia.scm.repository.util.NoneCachingWorkingCopyPool; -import sonia.scm.repository.util.WorkdirProvider; +import sonia.scm.repository.work.NoneCachingWorkingCopyPool; +import sonia.scm.repository.work.WorkdirProvider; import sonia.scm.web.HgRepositoryEnvironmentBuilder; import java.util.List; diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgModifyCommandTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgModifyCommandTest.java index 872151ab6b..d55005f675 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgModifyCommandTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgModifyCommandTest.java @@ -35,8 +35,8 @@ import sonia.scm.NotFoundException; import sonia.scm.repository.HgHookManager; import sonia.scm.repository.HgTestUtil; import sonia.scm.repository.Person; -import sonia.scm.repository.util.NoneCachingWorkingCopyPool; -import sonia.scm.repository.util.WorkdirProvider; +import sonia.scm.repository.work.NoneCachingWorkingCopyPool; +import sonia.scm.repository.work.WorkdirProvider; import sonia.scm.web.HgRepositoryEnvironmentBuilder; import java.io.File; diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactoryTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactoryTest.java index 9199a23c92..779b847087 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactoryTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactoryTest.java @@ -26,17 +26,15 @@ package sonia.scm.repository.spi; import com.aragost.javahg.Repository; import com.google.inject.util.Providers; -import org.assertj.core.api.Assertions; -import org.junit.Assert; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import sonia.scm.repository.HgHookManager; import sonia.scm.repository.HgTestUtil; -import sonia.scm.repository.util.CachingAllWorkingCopyPool; -import sonia.scm.repository.util.WorkdirProvider; -import sonia.scm.repository.util.WorkingCopy; +import sonia.scm.repository.work.CachingAllWorkingCopyPool; +import sonia.scm.repository.work.WorkdirProvider; +import sonia.scm.repository.work.WorkingCopy; import sonia.scm.web.HgRepositoryEnvironmentBuilder; import java.io.File; diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnWorkingCopyFactory.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnWorkingCopyFactory.java index 0c87f2d359..67793d1e90 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnWorkingCopyFactory.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnWorkingCopyFactory.java @@ -25,7 +25,7 @@ package sonia.scm.repository; import sonia.scm.repository.spi.SvnContext; -import sonia.scm.repository.util.WorkingCopyFactory; +import sonia.scm.repository.work.WorkingCopyFactory; import java.io.File; diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactory.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactory.java index 922eb3bc38..91c995c179 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactory.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactory.java @@ -35,9 +35,9 @@ import org.tmatesoft.svn.core.wc2.SvnTarget; import sonia.scm.repository.InternalRepositoryException; import sonia.scm.repository.Repository; import sonia.scm.repository.SvnWorkingCopyFactory; -import sonia.scm.repository.util.WorkingCopyPool; -import sonia.scm.repository.util.SimpleWorkingCopyFactory; -import sonia.scm.repository.util.WorkingCopyPool.ParentAndClone; +import sonia.scm.repository.work.WorkingCopyPool; +import sonia.scm.repository.work.SimpleWorkingCopyFactory; +import sonia.scm.repository.work.WorkingCopyPool.ParentAndClone; import javax.inject.Inject; import java.io.File; 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 index e9cbcd68b6..57b7a3ad68 100644 --- 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 @@ -34,7 +34,7 @@ import org.tmatesoft.svn.core.wc.SVNWCUtil; import sonia.scm.repository.InternalRepositoryException; import sonia.scm.repository.Repository; import sonia.scm.repository.SvnWorkingCopyFactory; -import sonia.scm.repository.util.WorkingCopy; +import sonia.scm.repository.work.WorkingCopy; import java.io.File; import java.io.IOException; diff --git a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactoryTest.java b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactoryTest.java index 120f7cc20b..66c51a94cb 100644 --- a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactoryTest.java +++ b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactoryTest.java @@ -30,9 +30,9 @@ import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.tmatesoft.svn.core.SVNException; import sonia.scm.repository.Repository; -import sonia.scm.repository.util.NoneCachingWorkingCopyPool; -import sonia.scm.repository.util.WorkdirProvider; -import sonia.scm.repository.util.WorkingCopy; +import sonia.scm.repository.work.NoneCachingWorkingCopyPool; +import sonia.scm.repository.work.WorkdirProvider; +import sonia.scm.repository.work.WorkingCopy; import java.io.File; import java.io.IOException; 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 index 029ad5cd07..dbace87411 100644 --- 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 @@ -33,9 +33,9 @@ import org.junit.Test; import org.junit.rules.TemporaryFolder; import sonia.scm.AlreadyExistsException; import sonia.scm.repository.Person; -import sonia.scm.repository.util.NoneCachingWorkingCopyPool; -import sonia.scm.repository.util.WorkdirProvider; -import sonia.scm.repository.util.WorkingCopy; +import sonia.scm.repository.work.NoneCachingWorkingCopyPool; +import sonia.scm.repository.work.WorkdirProvider; +import sonia.scm.repository.work.WorkingCopy; import java.io.File; import java.io.IOException; diff --git a/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/WorkingCopyPoolModule.java b/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/WorkingCopyPoolModule.java index 9ab838856c..63e9ce6cd4 100644 --- a/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/WorkingCopyPoolModule.java +++ b/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/WorkingCopyPoolModule.java @@ -26,10 +26,10 @@ package sonia.scm.lifecycle.modules; import com.google.inject.AbstractModule; import sonia.scm.plugin.PluginLoader; -import sonia.scm.repository.util.WorkingCopyPool; +import sonia.scm.repository.work.WorkingCopyPool; public class WorkingCopyPoolModule extends AbstractModule { - public static final String DEFAULT_WORKING_COPY_POOL_STRATEGY = "sonia.scm.repository.util.NoneCachingWorkingCopyPool"; + public static final String DEFAULT_WORKING_COPY_POOL_STRATEGY = "sonia.scm.repository.work.NoneCachingWorkingCopyPool"; public static final String WORKING_COPY_POOL_STRATEGY_PROPERTY = "scm.workingCopyPoolStrategy"; private final PluginLoader pluginLoader; From 62a47d016fb86267faaa0bc7cccaadfbb0a12228 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Sun, 10 May 2020 17:03:01 +0200 Subject: [PATCH 15/29] Document SimpleGitWorkingCopyFactory --- .../work/CachingAllWorkingCopyPool.java | 4 +- .../work/NoneCachingWorkingCopyPool.java | 4 +- .../work/SimpleWorkingCopyFactory.java | 184 ++++++++++++++++-- .../repository/work/WorkingCopyContext.java | 10 +- .../scm/repository/work/WorkingCopyPool.java | 5 +- .../work/CachingAllWorkingCopyPoolTest.java | 3 +- .../work/SimpleWorkingCopyFactoryTest.java | 17 +- .../sonia/scm/repository/spi/GitContext.java | 10 +- .../spi/SimpleGitWorkingCopyFactory.java | 7 +- .../scm/repository/spi/HgCommandContext.java | 10 +- .../spi/SimpleHgWorkingCopyFactory.java | 7 +- .../spi/SimpleSvnWorkingCopyFactory.java | 11 +- .../sonia/scm/repository/spi/SvnContext.java | 10 +- .../spi/SimpleSvnWorkingCopyFactoryTest.java | 2 +- 14 files changed, 226 insertions(+), 58 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/repository/work/CachingAllWorkingCopyPool.java b/scm-core/src/main/java/sonia/scm/repository/work/CachingAllWorkingCopyPool.java index f93a374c00..195e9e19d5 100644 --- a/scm-core/src/main/java/sonia/scm/repository/work/CachingAllWorkingCopyPool.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/CachingAllWorkingCopyPool.java @@ -28,12 +28,14 @@ import com.google.common.base.Stopwatch; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sonia.scm.repository.InternalRepositoryException; +import sonia.scm.repository.Repository; import sonia.scm.util.IOUtil; import javax.inject.Inject; import java.io.File; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Supplier; public class CachingAllWorkingCopyPool implements WorkingCopyPool { @@ -49,7 +51,7 @@ public class CachingAllWorkingCopyPool implements WorkingCopyPool { } @Override - public ParentAndClone getWorkingCopy(WorkingCopyContext workingCopyContext) { + public > ParentAndClone getWorkingCopy(WorkingCopyContext workingCopyContext) { String id = workingCopyContext.getScmRepository().getId(); File existingWorkdir = workdirs.remove(id); if (existingWorkdir != null) { diff --git a/scm-core/src/main/java/sonia/scm/repository/work/NoneCachingWorkingCopyPool.java b/scm-core/src/main/java/sonia/scm/repository/work/NoneCachingWorkingCopyPool.java index c5aef18b0e..4cc7acfce6 100644 --- a/scm-core/src/main/java/sonia/scm/repository/work/NoneCachingWorkingCopyPool.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/NoneCachingWorkingCopyPool.java @@ -24,10 +24,12 @@ package sonia.scm.repository.work; +import sonia.scm.repository.Repository; import sonia.scm.util.IOUtil; import javax.inject.Inject; import java.io.File; +import java.util.function.Supplier; public class NoneCachingWorkingCopyPool implements WorkingCopyPool { @@ -39,7 +41,7 @@ public class NoneCachingWorkingCopyPool implements WorkingCopyPool { } @Override - public ParentAndClone getWorkingCopy(WorkingCopyContext context) throws WorkingCopyFailedException { + public > ParentAndClone getWorkingCopy(WorkingCopyContext context) throws WorkingCopyFailedException { return context.getInitializer().initialize(workdirProvider.createNewWorkdir()); } diff --git a/scm-core/src/main/java/sonia/scm/repository/work/SimpleWorkingCopyFactory.java b/scm-core/src/main/java/sonia/scm/repository/work/SimpleWorkingCopyFactory.java index 76bb0a7b5e..ed75036641 100644 --- a/scm-core/src/main/java/sonia/scm/repository/work/SimpleWorkingCopyFactory.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/SimpleWorkingCopyFactory.java @@ -32,8 +32,166 @@ import sonia.scm.repository.Repository; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import java.io.File; +import java.util.function.Supplier; -public abstract class SimpleWorkingCopyFactory implements WorkingCopyFactory, ServletContextListener { +/** + * This class is responsible to govern the creation, the reuse and the destruction + * of working copies. For every repository type there has to be an implementation + * of this class to provide the repository specific logic to create, initialize, + * reclaim and clean up working copies. To do this, the following methods have to be + * implemented: + * + *
+ *
{@link #cloneRepository(C, File, String)}
+ *
Creates a new clone of the repository for the given context in the given + * directory with the given branch checked out (if branches are supported).
+ *
{@link #reclaimRepository(C, File, String)}
+ *
Reclaim the working directory with a already checked out clone of the + * repository given in the context, so that the directory is not modified in + * respect to the repository and the given branch is checked out (if branches + * are supported).
+ *
{@link #closeWorkingCopy(W)}
+ *
Closes resources allocated for the working copy, so that the directory can + * be put to the cache. Will be called at the end of the operation.
+ *
{@link #closeRepository(R)}
+ *
Closes resources allocated for the central repository.
+ *
+ *
+ *                     ┌─────────────┐          ┌───────────────────────────┐                                                      ┌───────────────┐          ┌───────────────┐
+ *                     │ModifyCommand│          │SimpleGitWorkingCopyFactory│                                                      │WorkingCopyPool│          │WorkdirProvider│
+ *                     └──────┬──────┘          └─────────────┬─────────────┘                                                      └───────┬───────┘          └───────┬───────┘
+ *                            │      createWorkingCopy        │                                                                            │                          │
+ *                            │──────────────────────────────>│                                                                            │                          │
+ *                            │                               │                                                                            │                          │
+ *                            │                               ────┐                                                                        │                          │
+ *                            │                                   │ createContext                                                          │                          │
+ *                            │                               <───┘                                                                        │                          │
+ *                            │                               │                                                                            │                          │
+ *                            │                               │        create          ┌─────────┐                                         │                          │
+ *                            │                               │──────────────────────> │Reclaimer│                                         │                          │
+ *                            │                               │                        └────┬────┘                                         │                          │
+ *                            │                               │                  create     │               ┌───────────┐                  │                          │
+ *                            │                               │───────────────────────────────────────────> │Initializer│                  │                          │
+ *                            │                               │                             │               └─────┬─────┘                  │                          │
+ *                            │                               │                             │getWorkingCopy       │                        │                          │
+ *                            │                               │───────────────────────────────────────────────────────────────────────────>│                          │
+ *                            │                               │                             │                     │                        │                          │
+ *                            │                               │                             │                     │                        │                          │
+ *                            │                               │                             │                     │                        │                          │
+ *                            │                               │                             │                     │                        │                          │
+ *                            │                               │                             │                   reclaim                    │                          │
+ *                            │                               │                             │<─────────────────────────────────────────────│                          │
+ *                            │                               │                             │                     │                        │                          │
+ *                            │                               │          reclaim            │                     │                        │                          │
+ *                            │                               │<────────────────────────────│                     │                        │                          │
+ *                            │                               │                             │                     │                        │                          │
+ *                            │                               │                             │                     │                        │                          │
+ *                            │       ╔══════╤════════════════╪═════════════════════════════╪═════════════════════╪════════════════════════╪══════════════════════════╪═════════════════╗
+ *                            │       ║ ALT  │  reclaim successful                          │                     │                        │                          │                 ║
+ *                            │       ╟──────┘                │                             │                     │                        │                          │                 ║
+ *                            │       ║                       │                             │                     │                        │                          │                 ║
+ *                            │       ║                       │───────────────────────────────────────────────────────────────────────────>│                          │                 ║
+ *                            │       ╠═══════════════════════╪═════════════════════════════╪═════════════════════╪════════════════════════╪══════════════════════════╪═════════════════╣
+ *                            │       ║ [reclaim fails; create new]                         │                     │                        │                          │                 ║
+ *                            │       ║                       │                      ReclaimFailedException       │                        │                          │                 ║
+ *                            │       ║                       │───────────────────────────────────────────────────────────────────────────X│                          │                 ║
+ *                            │       ║                       │                             │                     │                        │                          │                 ║
+ *                            │       ║                       │                             │                     │                        │    createNewWorkdir      │                 ║
+ *                            │       ║                       │                             │                     │                        │─────────────────────────>│                 ║
+ *                            │       ║                       │                             │                     │                        │                          │                 ║
+ *                            │       ║                       │                             │                     │                        │                          │                 ║
+ *                            │       ║                       │                             │                     │                        │<─────────────────────────│                 ║
+ *                            │       ║                       │                             │                     │                        │                          │                 ║
+ *                            │       ║                       │                             │                     │      initialize        │                          │                 ║
+ *                            │       ║                       │                             │                     │<───────────────────────│                          │                 ║
+ *                            │       ║                       │                             │                     │                        │                          │                 ║
+ *                            │       ║                       │                    initialize                     │                        │                          │                 ║
+ *                            │       ║                       │<──────────────────────────────────────────────────│                        │                          │                 ║
+ *                            │       ║                       │                             │                     │                        │                          │                 ║
+ *                            │       ║                       │                             │                     │                        │                          │                 ║
+ *                            │       ║                       │───────────────────────────────────────────────────────────────────────────>│                          │                 ║
+ *                            │       ╚═══════════════════════╪═════════════════════════════╪═════════════════════╪════════════════════════╪══════════════════════════╪═════════════════╝
+ *                            │                               │                             │                     │                        │                          │
+ *                            │                               │                             │                     │                        │                          │
+ *                            │                               │<───────────────────────────────────────────────────────────────────────────│                          │                        │
+ *                            │                               │                             │                     │                        │                          │                        │
+ *                            │                               │                             │                     │                        │                          │                  ┌───────────┐
+ *                            │                               │────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────> │WorkingCopy│
+ *                            │                               │                             │                     │                        │                          │                  └─────┬─────┘
+ *                            │         WorkingCopy           │                             │                     │                        │                          │                        │
+ *                            │<──────────────────────────────│                             │                     │                        │                          │                        │
+ *                            │                               │                             │                     │                        │                          │                        │
+ *                            .                               .                             .                     .                        .                          .                        .
+ *                            .                               .                             .                     .                        .                          .                        .
+ *                            .                               .                             .                     .                        .                          .                        .
+ *                            .                               .                             .                     .                        .                          .                        .
+ *                            │                               │                             │              doWork │                        │                          │                        │
+ *                            │───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────>│
+ *                            │                               │                             │                     │                        │                          │                        │
+ *                            .                               .                             .                     .                        .                          .                        .
+ *                            .                               .                             .                     .                        .                          .                        .
+ *                            .                               .                             .                     .                        .                          .                        .
+ *                            .                               .                             .                     .                        .                          .                        .
+ *                            │                               │                             │               close │                        │                          │                        │
+ *                            │───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────>│
+ *                            │                               │                             │                     │                        │                          │                        │
+ *                            │                               │                             │                     │         close          │                          │                        │
+ *                            │                               │<───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────│
+ *                            │                               │                             │                     │                        │                          │                        │
+ *                            │                               ────┐                         │                     │                        │                          │                        │
+ *                            │                                   │ closeWorkingCopy        │                     │                        │                          │                        │
+ *                            │                               <───┘                         │                     │                        │                          │                        │
+ *                            │                               │                             │                     │                        │                          │                        │
+ *                            │                               ────┐                         │                     │                        │                          │                        │
+ *                            │                                   │ closeRepository         │                     │                        │                          │                        │
+ *                            │                               <───┘                         │                     │                        │                          │                        │
+ *                            │                               │                             │                     │                        │                          │                        │
+ *                            │                               │                             │ contextClosed       │                        │                          │                        │
+ *                            │                               │───────────────────────────────────────────────────────────────────────────>│                          │                        │
+ *                     ┌──────┴──────┐          ┌─────────────┴─────────────┐          ┌────┴────┐          ┌─────┴─────┐          ┌───────┴───────┐          ┌───────┴───────┐          ┌─────┴─────┐
+ *                     │ModifyCommand│          │SimpleGitWorkingCopyFactory│          │Reclaimer│          │Initializer│          │WorkingCopyPool│          │WorkdirProvider│          │WorkingCopy│
+ *                     └─────────────┘          └───────────────────────────┘          └─────────┘          └───────────┘          └───────────────┘          └───────────────┘          └───────────┘
+ * 
+ * + * @param Type of central repository location + * @param Type of working copy for repository + * @param Type of repository context + */ +/* +http://www.plantuml.com/plantuml/uml/fLH1QiCm4Bph5JeRaWUeO0AcAJsqXBJGiv0sOQcaDPBSn7rzQw8OLG4beJThTsOyE_9w5QBqSR26lP36tTYHjTBfHVk6jZVmXF63_2UwVKVzk9OgaX-vuCg3Z92rM0LV5HCdgOvSX6Eio_0jA2FHWc-QnBj2U7OOKHhylfcIrJP4HkmXXx6zfw7dxtxaaRW_sM45Pz7EFiKPCbUgOSnmQU9PdOT1AGXXDvYwyvONFXYO0BFCJg893-dck8D3NUrOgeaqmlfN1_JZKK4VaTpby5D1ezzu-a8DFgN-2eVKO0LWqPQXNsfczoXmVcPPkPfhnhaxGwSlxTJUTVFdrJHNlFpPI94xOylbibpOh2qqJQThA6KeG3vSDSC4ho1ke6VrVofjeQU0q_c-VLQd7qqtQMYs0gS7Qtu0 +@startuml +ModifyCommand->SimpleGitWorkingCopyFactory : createWorkingCopy +SimpleGitWorkingCopyFactory->SimpleGitWorkingCopyFactory:createContext +SimpleGitWorkingCopyFactory-> Reclaimer**:create +SimpleGitWorkingCopyFactory-> Initializer**:create +SimpleGitWorkingCopyFactory->WorkingCopyPool:getWorkingCopy +group Try to reclaim +WorkingCopyPool->Reclaimer:reclaim +Reclaimer->SimpleGitWorkingCopyFactory:reclaim +alt reclaim successful +SimpleGitWorkingCopyFactory->> WorkingCopyPool +else reclaim fails; create new +SimpleGitWorkingCopyFactory->x WorkingCopyPool:ReclaimFailedException +WorkingCopyPool->WorkdirProvider:createNewWorkdir +WorkdirProvider->>WorkingCopyPool +WorkingCopyPool->Initializer:initialize +Initializer->SimpleGitWorkingCopyFactory:initialize +SimpleGitWorkingCopyFactory->> WorkingCopyPool +end +WorkingCopyPool->>SimpleGitWorkingCopyFactory +SimpleGitWorkingCopyFactory->WorkingCopy** +SimpleGitWorkingCopyFactory->>ModifyCommand: WorkingCopy +... +ModifyCommand->WorkingCopy:doWork +... +ModifyCommand->WorkingCopy:close +WorkingCopy->SimpleGitWorkingCopyFactory:close +SimpleGitWorkingCopyFactory->SimpleGitWorkingCopyFactory:closeWorkingCopy +SimpleGitWorkingCopyFactory->SimpleGitWorkingCopyFactory:closeRepository +SimpleGitWorkingCopyFactory->WorkingCopyPool:contextClosed +@enduml +*/ +public abstract class SimpleWorkingCopyFactory> implements WorkingCopyFactory, ServletContextListener { private static final Logger LOG = LoggerFactory.getLogger(SimpleWorkingCopyFactory.class); @@ -50,13 +208,12 @@ public abstract class SimpleWorkingCopyFactory implements WorkingCopyFa WorkingCopyPool.ParentAndClone parentAndClone = workingCopyPool.getWorkingCopy(workingCopyContext); return new WorkingCopy<>(parentAndClone.getClone(), parentAndClone.getParent(), () -> this.close(workingCopyContext, parentAndClone), parentAndClone.getDirectory()); } catch (WorkingCopyFailedException e) { - throw new InternalRepositoryException(getScmRepository(repositoryContext), "could not create working copy for repository in temporary directory", e); + throw new InternalRepositoryException(repositoryContext.get(), "could not create working copy for repository in temporary directory", e); } } private WorkingCopyContext createWorkingCopyContext(C repositoryContext, String initialBranch) { return new WorkingCopyContext<>( - getScmRepository(repositoryContext), initialBranch, repositoryContext, newFolder -> cloneRepository(repositoryContext, newFolder, initialBranch), @@ -65,16 +222,16 @@ public abstract class SimpleWorkingCopyFactory implements WorkingCopyFa } private void close(WorkingCopyContext workingCopyContext, WorkingCopyPool.ParentAndClone parentAndClone) { + try { + closeWorkingCopy(parentAndClone.getClone()); + } catch (Exception e) { + LOG.warn("could not close clone for {} in directory {}", workingCopyContext.getScmRepository(), parentAndClone.getDirectory(), e); + } try { closeRepository(parentAndClone.getParent()); } catch (Exception e) { LOG.warn("could not close central repository for {}", workingCopyContext.getScmRepository(), e); } - try { - closeWorkingCopyInternal(parentAndClone.getClone()); - } catch (Exception e) { - LOG.warn("could not close clone for {} in directory {}", workingCopyContext.getScmRepository(), parentAndClone.getDirectory(), e); - } try { workingCopyPool.contextClosed(workingCopyContext, parentAndClone.getDirectory()); } catch (Exception e) { @@ -102,18 +259,17 @@ public abstract class SimpleWorkingCopyFactory implements WorkingCopyFa WorkingCopyPool.ParentAndClone reclaim(File target) throws ReclaimFailedException; } - protected abstract Repository getScmRepository(C context); + protected abstract WorkingCopyPool.ParentAndClone cloneRepository(C context, File target, String initialBranch) throws WorkingCopyFailedException; + + protected abstract WorkingCopyPool.ParentAndClone reclaimRepository(C context, File target, String initialBranch) throws ReclaimFailedException; @SuppressWarnings("squid:S00112") // We do allow implementations to throw arbitrary exceptions here, so that we can handle them in closeCentral protected abstract void closeRepository(R repository) throws Exception; + @SuppressWarnings("squid:S00112") // We do allow implementations to throw arbitrary exceptions here, so that we can handle them in closeWorkingCopy - protected abstract void closeWorkingCopyInternal(W workingCopy) throws Exception; - - protected abstract WorkingCopyPool.ParentAndClone cloneRepository(C context, File target, String initialBranch) throws WorkingCopyFailedException; - - protected abstract WorkingCopyPool.ParentAndClone reclaimRepository(C context, File target, String initialBranch) throws ReclaimFailedException; + protected abstract void closeWorkingCopy(W workingCopy) throws Exception; public static class ReclaimFailedException extends Exception { public ReclaimFailedException(String message) { diff --git a/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyContext.java b/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyContext.java index 9033a1b461..86fda237a3 100644 --- a/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyContext.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyContext.java @@ -26,15 +26,15 @@ package sonia.scm.repository.work; import sonia.scm.repository.Repository; -public class WorkingCopyContext { - private final Repository scmRepository; +import java.util.function.Supplier; + +public class WorkingCopyContext> { private final String requestedBranch; private final C context; private final SimpleWorkingCopyFactory.WorkingCopyInitializer initializer; private final SimpleWorkingCopyFactory.WorkingCopyReclaimer reclaimer; - public WorkingCopyContext(Repository scmRepository, String requestedBranch, C context, SimpleWorkingCopyFactory.WorkingCopyInitializer initializer, SimpleWorkingCopyFactory.WorkingCopyReclaimer reclaimer) { - this.scmRepository = scmRepository; + public WorkingCopyContext(String requestedBranch, C context, SimpleWorkingCopyFactory.WorkingCopyInitializer initializer, SimpleWorkingCopyFactory.WorkingCopyReclaimer reclaimer) { this.requestedBranch = requestedBranch; this.context = context; this.initializer = initializer; @@ -42,7 +42,7 @@ public class WorkingCopyContext { } public Repository getScmRepository() { - return scmRepository; + return context.get(); } public String getRequestedBranch() { diff --git a/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyPool.java b/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyPool.java index dfbaac91b9..4f261a5601 100644 --- a/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyPool.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyPool.java @@ -24,10 +24,13 @@ package sonia.scm.repository.work; +import sonia.scm.repository.Repository; + import java.io.File; +import java.util.function.Supplier; public interface WorkingCopyPool { - ParentAndClone getWorkingCopy(WorkingCopyContext context) throws WorkingCopyFailedException; + > ParentAndClone getWorkingCopy(WorkingCopyContext context) throws WorkingCopyFailedException; void contextClosed(WorkingCopyContext workingCopyContext, File workdir); diff --git a/scm-core/src/test/java/sonia/scm/repository/work/CachingAllWorkingCopyPoolTest.java b/scm-core/src/test/java/sonia/scm/repository/work/CachingAllWorkingCopyPoolTest.java index 74ccbe029b..fbea30a3f3 100644 --- a/scm-core/src/test/java/sonia/scm/repository/work/CachingAllWorkingCopyPoolTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/work/CachingAllWorkingCopyPoolTest.java @@ -35,6 +35,7 @@ import sonia.scm.repository.Repository; import java.io.File; import java.nio.file.Path; +import java.util.function.Supplier; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; @@ -54,7 +55,7 @@ class CachingAllWorkingCopyPoolTest { CachingAllWorkingCopyPool cachingAllWorkingCopyPool; @Mock - WorkingCopyContext workingCopyContext; + WorkingCopyContext> workingCopyContext; @Mock SimpleWorkingCopyFactory.WorkingCopyInitializer initializer; @Mock diff --git a/scm-core/src/test/java/sonia/scm/repository/work/SimpleWorkingCopyFactoryTest.java b/scm-core/src/test/java/sonia/scm/repository/work/SimpleWorkingCopyFactoryTest.java index fd12e578dd..798e08c88a 100644 --- a/scm-core/src/test/java/sonia/scm/repository/work/SimpleWorkingCopyFactoryTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/work/SimpleWorkingCopyFactoryTest.java @@ -34,6 +34,7 @@ import sonia.scm.util.IOUtil; import java.io.Closeable; import java.io.File; import java.io.IOException; +import java.util.function.Supplier; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; @@ -60,7 +61,7 @@ public class SimpleWorkingCopyFactoryTest { WorkdirProvider workdirProvider = new WorkdirProvider(temporaryFolder.newFolder()); WorkingCopyPool configurableTestWorkingCopyPool = new WorkingCopyPool() { @Override - public ParentAndClone getWorkingCopy(WorkingCopyContext context) throws WorkingCopyFailedException { + public > ParentAndClone getWorkingCopy(WorkingCopyContext context) throws WorkingCopyFailedException { workdir = workdirProvider.createNewWorkdir(); return context.getInitializer().initialize(workdir); } @@ -77,11 +78,6 @@ public class SimpleWorkingCopyFactoryTest { } }; simpleWorkingCopyFactory = new SimpleWorkingCopyFactory(configurableTestWorkingCopyPool) { - @Override - protected Repository getScmRepository(Context context) { - return REPOSITORY; - } - @Override protected void closeRepository(Closeable repository) throws IOException { repository.close(); @@ -93,7 +89,7 @@ public class SimpleWorkingCopyFactoryTest { } @Override - protected void closeWorkingCopyInternal(Closeable workingCopy) throws Exception { + protected void closeWorkingCopy(Closeable workingCopy) throws Exception { workingCopy.close(); } @@ -155,5 +151,10 @@ public class SimpleWorkingCopyFactoryTest { } } - private static class Context {} + private static class Context implements Supplier { + @Override + public Repository get() { + return REPOSITORY; + } + } } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitContext.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitContext.java index c66f5cab55..3763e57939 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitContext.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitContext.java @@ -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; //~--- non-JDK imports -------------------------------------------------------- @@ -39,12 +39,13 @@ import sonia.scm.repository.Repository; import java.io.Closeable; import java.io.File; import java.io.IOException; +import java.util.function.Supplier; /** * * @author Sebastian Sdorra */ -public class GitContext implements Closeable +public class GitContext implements Closeable, Supplier { /** @@ -108,6 +109,11 @@ public class GitContext implements Closeable return repository; } + @Override + public Repository get() { + return getRepository(); + } + File getDirectory() { return directory; } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactory.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactory.java index ecd874e20c..a8a84fdf92 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactory.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactory.java @@ -133,14 +133,9 @@ public class SimpleGitWorkingCopyFactory extends SimpleWorkingCopyFactory { /** Field description */ @@ -155,6 +156,11 @@ public class HgCommandContext implements Closeable return scmRepository; } + @Override + public sonia.scm.repository.Repository get() { + return getScmRepository(); + } + //~--- fields --------------------------------------------------------------- /** Field description */ diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactory.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactory.java index 9285cf3417..170d57b421 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactory.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactory.java @@ -104,15 +104,10 @@ public class SimpleHgWorkingCopyFactory extends SimpleWorkingCopyFactory cloneRepository(SvnContext context, File workingCopy, String initialBranch) { @@ -63,7 +58,7 @@ public class SimpleSvnWorkingCopyFactory extends SimpleWorkingCopyFactory { private static final Logger LOG = LoggerFactory.getLogger(SvnContext.class); @@ -64,6 +65,11 @@ public class SvnContext implements Closeable { return repository; } + @Override + public Repository get() { + return getRepository(); + } + public File getDirectory() { return directory; } diff --git a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactoryTest.java b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactoryTest.java index 66c51a94cb..9cac5f205d 100644 --- a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactoryTest.java +++ b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactoryTest.java @@ -96,7 +96,7 @@ public class SimpleSvnWorkingCopyFactoryTest extends AbstractSvnCommandTestBase @Test public void shouldReturnRepository() { SimpleSvnWorkingCopyFactory factory = new SimpleSvnWorkingCopyFactory(new NoneCachingWorkingCopyPool(workdirProvider)); - Repository scmRepository = factory.getScmRepository(createContext()); + Repository scmRepository = createContext().getRepository(); assertThat(scmRepository).isSameAs(repository); } } From 4c73f27389c6f089fbabd273c75f6a2e83f4ef10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Sun, 10 May 2020 21:53:18 +0200 Subject: [PATCH 16/29] Make reclaimer and initializer top level classes --- .../work/CachingAllWorkingCopyPool.java | 5 +- .../work/NoneCachingWorkingCopyPool.java | 2 +- .../work/SimpleWorkingCopyFactory.java | 49 ++++------- .../work/CachingAllWorkingCopyPoolTest.java | 17 ++-- .../work/SimpleWorkingCopyFactoryTest.java | 15 ++-- .../spi/SimpleGitWorkingCopyFactory.java | 86 ++++++++++--------- .../spi/SimpleGitWorkingCopyFactoryTest.java | 10 +-- .../spi/SimpleHgWorkingCopyFactory.java | 53 ++++++------ .../spi/SimpleSvnWorkingCopyFactory.java | 61 ++++++------- 9 files changed, 152 insertions(+), 146 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/repository/work/CachingAllWorkingCopyPool.java b/scm-core/src/main/java/sonia/scm/repository/work/CachingAllWorkingCopyPool.java index 195e9e19d5..3cf5074e74 100644 --- a/scm-core/src/main/java/sonia/scm/repository/work/CachingAllWorkingCopyPool.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/CachingAllWorkingCopyPool.java @@ -57,7 +57,7 @@ public class CachingAllWorkingCopyPool implements WorkingCopyPool { if (existingWorkdir != null) { Stopwatch stopwatch = Stopwatch.createStarted(); try { - ParentAndClone reclaimed = workingCopyContext.getReclaimer().reclaim(existingWorkdir); + ParentAndClone reclaimed = workingCopyContext.getReclaimer().reclaim(existingWorkdir, workingCopyContext.getRequestedBranch()); LOG.debug("reclaimed workdir for {} in path {} in {}", workingCopyContext.getScmRepository().getNamespaceAndName(), existingWorkdir, stopwatch.stop()); return reclaimed; } catch (SimpleWorkingCopyFactory.ReclaimFailedException e) { @@ -75,7 +75,8 @@ public class CachingAllWorkingCopyPool implements WorkingCopyPool { private ParentAndClone createNewWorkdir(WorkingCopyContext workingCopyContext) throws WorkingCopyFailedException { Stopwatch stopwatch = Stopwatch.createStarted(); File newWorkdir = workdirProvider.createNewWorkdir(); - ParentAndClone parentAndClone = workingCopyContext.getInitializer().initialize(newWorkdir); + SimpleWorkingCopyFactory.WorkingCopyInitializer initializer = workingCopyContext.getInitializer(); + ParentAndClone parentAndClone = initializer.initialize(newWorkdir, workingCopyContext.getRequestedBranch()); LOG.debug("initialized new workdir for {} in path {} in {}", workingCopyContext.getScmRepository().getNamespaceAndName(), newWorkdir, stopwatch.stop()); return parentAndClone; } diff --git a/scm-core/src/main/java/sonia/scm/repository/work/NoneCachingWorkingCopyPool.java b/scm-core/src/main/java/sonia/scm/repository/work/NoneCachingWorkingCopyPool.java index 4cc7acfce6..ccc3ddc658 100644 --- a/scm-core/src/main/java/sonia/scm/repository/work/NoneCachingWorkingCopyPool.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/NoneCachingWorkingCopyPool.java @@ -42,7 +42,7 @@ public class NoneCachingWorkingCopyPool implements WorkingCopyPool { @Override public > ParentAndClone getWorkingCopy(WorkingCopyContext context) throws WorkingCopyFailedException { - return context.getInitializer().initialize(workdirProvider.createNewWorkdir()); + return context.getInitializer().initialize(workdirProvider.createNewWorkdir(), context.getRequestedBranch()); } @Override diff --git a/scm-core/src/main/java/sonia/scm/repository/work/SimpleWorkingCopyFactory.java b/scm-core/src/main/java/sonia/scm/repository/work/SimpleWorkingCopyFactory.java index ed75036641..cb6f233b1c 100644 --- a/scm-core/src/main/java/sonia/scm/repository/work/SimpleWorkingCopyFactory.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/SimpleWorkingCopyFactory.java @@ -42,10 +42,10 @@ import java.util.function.Supplier; * implemented: * *
- *
{@link #cloneRepository(C, File, String)}
+ *
{@link #getInitializer(C, File, String)}
*
Creates a new clone of the repository for the given context in the given * directory with the given branch checked out (if branches are supported).
- *
{@link #reclaimRepository(C, File, String)}
+ *
{@link #getReclaimer(C, File, String)}
*
Reclaim the working directory with a already checked out clone of the * repository given in the context, so that the directory is not modified in * respect to the repository and the given branch is checked out (if branches @@ -82,19 +82,16 @@ import java.util.function.Supplier; * │ │ │ reclaim │ │ * │ │ │<─────────────────────────────────────────────│ │ * │ │ │ │ │ │ - * │ │ reclaim │ │ │ │ - * │ │<────────────────────────────│ │ │ │ - * │ │ │ │ │ │ * │ │ │ │ │ │ * │ ╔══════╤════════════════╪═════════════════════════════╪═════════════════════╪════════════════════════╪══════════════════════════╪═════════════════╗ * │ ║ ALT │ reclaim successful │ │ │ │ ║ * │ ╟──────┘ │ │ │ │ │ ║ * │ ║ │ │ │ │ │ ║ - * │ ║ │───────────────────────────────────────────────────────────────────────────>│ │ ║ + * │ ║ │ │─────────────────────────────────────────────>│ │ ║ * │ ╠═══════════════════════╪═════════════════════════════╪═════════════════════╪════════════════════════╪══════════════════════════╪═════════════════╣ * │ ║ [reclaim fails; create new] │ │ │ │ ║ - * │ ║ │ ReclaimFailedException │ │ │ ║ - * │ ║ │───────────────────────────────────────────────────────────────────────────X│ │ ║ + * │ ║ │ ReclaimFailedException │ │ │ ║ + * │ ║ │───────────────────────────────────────────────────────────────────────────>│ │ ║ * │ ║ │ │ │ │ │ ║ * │ ║ │ │ │ │ createNewWorkdir │ ║ * │ ║ │ │ │ │─────────────────────────>│ ║ @@ -105,16 +102,13 @@ import java.util.function.Supplier; * │ ║ │ │ │ initialize │ │ ║ * │ ║ │ │ │<───────────────────────│ │ ║ * │ ║ │ │ │ │ │ ║ - * │ ║ │ initialize │ │ │ ║ - * │ ║ │<──────────────────────────────────────────────────│ │ │ ║ * │ ║ │ │ │ │ │ ║ - * │ ║ │ │ │ │ │ ║ - * │ ║ │───────────────────────────────────────────────────────────────────────────>│ │ ║ + * │ ║ │ │ │───────────────────────>│ │ ║ * │ ╚═══════════════════════╪═════════════════════════════╪═════════════════════╪════════════════════════╪══════════════════════════╪═════════════════╝ * │ │ │ │ │ │ + * │ │ │ParentAndClone │ │ │ + * │ │<───────────────────────────────────────────────────────────────────────────│ │ * │ │ │ │ │ │ - * │ │<───────────────────────────────────────────────────────────────────────────│ │ │ - * │ │ │ │ │ │ │ * │ │ │ │ │ │ ┌───────────┐ * │ │────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────> │WorkingCopy│ * │ │ │ │ │ │ └─────┬─────┘ @@ -148,17 +142,14 @@ import java.util.function.Supplier; * │ │ │ │ │ │ │ * │ │ │ contextClosed │ │ │ │ * │ │───────────────────────────────────────────────────────────────────────────>│ │ │ - * ┌──────┴──────┐ ┌─────────────┴─────────────┐ ┌────┴────┐ ┌─────┴─────┐ ┌───────┴───────┐ ┌───────┴───────┐ ┌─────┴─────┐ - * │ModifyCommand│ │SimpleGitWorkingCopyFactory│ │Reclaimer│ │Initializer│ │WorkingCopyPool│ │WorkdirProvider│ │WorkingCopy│ - * └─────────────┘ └───────────────────────────┘ └─────────┘ └───────────┘ └───────────────┘ └───────────────┘ └───────────┘ * - * + * * @param Type of central repository location * @param Type of working copy for repository * @param Type of repository context */ /* -http://www.plantuml.com/plantuml/uml/fLH1QiCm4Bph5JeRaWUeO0AcAJsqXBJGiv0sOQcaDPBSn7rzQw8OLG4beJThTsOyE_9w5QBqSR26lP36tTYHjTBfHVk6jZVmXF63_2UwVKVzk9OgaX-vuCg3Z92rM0LV5HCdgOvSX6Eio_0jA2FHWc-QnBj2U7OOKHhylfcIrJP4HkmXXx6zfw7dxtxaaRW_sM45Pz7EFiKPCbUgOSnmQU9PdOT1AGXXDvYwyvONFXYO0BFCJg893-dck8D3NUrOgeaqmlfN1_JZKK4VaTpby5D1ezzu-a8DFgN-2eVKO0LWqPQXNsfczoXmVcPPkPfhnhaxGwSlxTJUTVFdrJHNlFpPI94xOylbibpOh2qqJQThA6KeG3vSDSC4ho1ke6VrVofjeQU0q_c-VLQd7qqtQMYs0gS7Qtu0 +http://www.plantuml.com/plantuml/uml/fPF1QiCm38RlVWgV0-a3U10wmZfss2ZTO6TZgqLCiOBjhCsUVeIcmKkPcx5RB7t_7qcsrY5g7xk6n3DRtFSrDursjgnUiMa97Z6-i_z0TwYvxJVQHFQzLD9uq16IbCZmMJDrjghPHJZ5l8tSWI6D3VYY67Kt14yE8sh2hyMI9BPb9dM051C7prqhttml8qj_BaVCD6KrrQakYAPumMNeZ84GzXs92IohIivi1520IRJNIE5k7BnqSCotSPgxgV5N6uq4zk5ae8t8xhhs8M3HRpr_eWK_3kq5ZcD2p82oci_isZEv1eNJjvZ2l_JlxBLLzYrjjGSNxvsjYTtoYowAF5hzs0sL5YfMgzLyTPAqiZoSRb66E43IQtvbHZn3B90dyNywxQ3bWCFvRvjbpYjV3nvMhC7Phg5l @startuml ModifyCommand->SimpleGitWorkingCopyFactory : createWorkingCopy SimpleGitWorkingCopyFactory->SimpleGitWorkingCopyFactory:createContext @@ -167,18 +158,16 @@ SimpleGitWorkingCopyFactory-> Initializer**:create SimpleGitWorkingCopyFactory->WorkingCopyPool:getWorkingCopy group Try to reclaim WorkingCopyPool->Reclaimer:reclaim -Reclaimer->SimpleGitWorkingCopyFactory:reclaim alt reclaim successful -SimpleGitWorkingCopyFactory->> WorkingCopyPool +Reclaimer->> WorkingCopyPool else reclaim fails; create new SimpleGitWorkingCopyFactory->x WorkingCopyPool:ReclaimFailedException WorkingCopyPool->WorkdirProvider:createNewWorkdir WorkdirProvider->>WorkingCopyPool WorkingCopyPool->Initializer:initialize -Initializer->SimpleGitWorkingCopyFactory:initialize -SimpleGitWorkingCopyFactory->> WorkingCopyPool +Initializer->> WorkingCopyPool end -WorkingCopyPool->>SimpleGitWorkingCopyFactory +WorkingCopyPool->>SimpleGitWorkingCopyFactory:ParentAndClone SimpleGitWorkingCopyFactory->WorkingCopy** SimpleGitWorkingCopyFactory->>ModifyCommand: WorkingCopy ... @@ -216,8 +205,8 @@ public abstract class SimpleWorkingCopyFactory( initialBranch, repositoryContext, - newFolder -> cloneRepository(repositoryContext, newFolder, initialBranch), - cachedFolder -> reclaimRepository(repositoryContext, cachedFolder, initialBranch) + getInitializer(repositoryContext), + getReclaimer(repositoryContext) ); } @@ -251,17 +240,17 @@ public abstract class SimpleWorkingCopyFactory { - WorkingCopyPool.ParentAndClone initialize(File target) throws WorkingCopyFailedException; + WorkingCopyPool.ParentAndClone initialize(File target, String initialBranch) throws WorkingCopyFailedException; } @FunctionalInterface public interface WorkingCopyReclaimer { - WorkingCopyPool.ParentAndClone reclaim(File target) throws ReclaimFailedException; + WorkingCopyPool.ParentAndClone reclaim(File target, String initialBranch) throws ReclaimFailedException; } - protected abstract WorkingCopyPool.ParentAndClone cloneRepository(C context, File target, String initialBranch) throws WorkingCopyFailedException; + protected abstract WorkingCopyInitializer getInitializer(C context); - protected abstract WorkingCopyPool.ParentAndClone reclaimRepository(C context, File target, String initialBranch) throws ReclaimFailedException; + protected abstract WorkingCopyReclaimer getReclaimer(C context); @SuppressWarnings("squid:S00112") // We do allow implementations to throw arbitrary exceptions here, so that we can handle them in closeCentral diff --git a/scm-core/src/test/java/sonia/scm/repository/work/CachingAllWorkingCopyPoolTest.java b/scm-core/src/test/java/sonia/scm/repository/work/CachingAllWorkingCopyPoolTest.java index fbea30a3f3..102e4c2098 100644 --- a/scm-core/src/test/java/sonia/scm/repository/work/CachingAllWorkingCopyPoolTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/work/CachingAllWorkingCopyPoolTest.java @@ -39,6 +39,7 @@ import java.util.function.Supplier; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -66,9 +67,9 @@ class CachingAllWorkingCopyPoolTest { lenient().when(workingCopyContext.getInitializer()).thenReturn(initializer); lenient().when(workingCopyContext.getReclaimer()).thenReturn(reclaimer); - lenient().when(initializer.initialize(any())) + lenient().when(initializer.initialize(any(), any())) .thenAnswer(invocationOnMock -> new WorkingCopyPool.ParentAndClone<>(null, null, invocationOnMock.getArgument(0, File.class))); - lenient().when(reclaimer.reclaim(any())) + lenient().when(reclaimer.reclaim(any(), any())) .thenAnswer(invocationOnMock -> new WorkingCopyPool.ParentAndClone<>(null, null, invocationOnMock.getArgument(0, File.class))); } @@ -79,7 +80,7 @@ class CachingAllWorkingCopyPoolTest { WorkingCopyPool.ParentAndClone workdir = cachingAllWorkingCopyPool.getWorkingCopy(workingCopyContext); - verify(initializer).initialize(temp.toFile()); + verify(initializer).initialize(temp.toFile(), null); } @Test @@ -91,8 +92,8 @@ class CachingAllWorkingCopyPoolTest { cachingAllWorkingCopyPool.contextClosed(workingCopyContext, firstWorkdir.getDirectory()); WorkingCopyPool.ParentAndClone secondWorkdir = cachingAllWorkingCopyPool.getWorkingCopy(workingCopyContext); - verify(initializer).initialize(temp.toFile()); - verify(reclaimer).reclaim(temp.toFile()); + verify(initializer).initialize(temp.toFile(), null); + verify(reclaimer).reclaim(temp.toFile(), null); assertThat(secondWorkdir.getDirectory()).isEqualTo(temp.toFile()); } @@ -112,9 +113,9 @@ class CachingAllWorkingCopyPoolTest { cachingAllWorkingCopyPool.contextClosed(workingCopyContext, firstWorkdir.getDirectory()); cachingAllWorkingCopyPool.contextClosed(workingCopyContext, secondWorkdir.getDirectory()); - verify(reclaimer, never()).reclaim(any()); - verify(initializer).initialize(firstDirectory); - verify(initializer).initialize(secondDirectory); + verify(reclaimer, never()).reclaim(any(), any()); + verify(initializer).initialize(firstDirectory, null); + verify(initializer).initialize(secondDirectory, null); assertThat(firstWorkdir.getDirectory()).isNotEqualTo(secondWorkdir.getDirectory()); assertThat(firstWorkdir.getDirectory()).exists(); assertThat(secondWorkdir.getDirectory()).doesNotExist(); diff --git a/scm-core/src/test/java/sonia/scm/repository/work/SimpleWorkingCopyFactoryTest.java b/scm-core/src/test/java/sonia/scm/repository/work/SimpleWorkingCopyFactoryTest.java index 798e08c88a..158e8fbb72 100644 --- a/scm-core/src/test/java/sonia/scm/repository/work/SimpleWorkingCopyFactoryTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/work/SimpleWorkingCopyFactoryTest.java @@ -63,7 +63,7 @@ public class SimpleWorkingCopyFactoryTest { @Override public > ParentAndClone getWorkingCopy(WorkingCopyContext context) throws WorkingCopyFailedException { workdir = workdirProvider.createNewWorkdir(); - return context.getInitializer().initialize(workdir); + return context.getInitializer().initialize(workdir, context.getRequestedBranch()); } @Override @@ -84,8 +84,9 @@ public class SimpleWorkingCopyFactoryTest { } @Override - protected WorkingCopyPool.ParentAndClone reclaimRepository(Context context, File target, String initialBranch) { - throw new UnsupportedOperationException(); + protected WorkingCopyReclaimer< + Closeable, Closeable> getReclaimer(Context context) { + return (target, initialBranch) -> {throw new UnsupportedOperationException();}; } @Override @@ -94,9 +95,11 @@ public class SimpleWorkingCopyFactoryTest { } @Override - protected WorkingCopyPool.ParentAndClone cloneRepository(Context context, File target, String initialBranch) { - initialBranchForLastCloneCall = initialBranch; - return new WorkingCopyPool.ParentAndClone<>(parent, clone, target); + protected WorkingCopyInitializer getInitializer(Context context) { + return (target, initialBranch) -> { + initialBranchForLastCloneCall = initialBranch; + return new WorkingCopyPool.ParentAndClone<>(parent, clone, target); + }; } }; } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactory.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactory.java index a8a84fdf92..5ce8f757b8 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactory.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactory.java @@ -58,53 +58,57 @@ public class SimpleGitWorkingCopyFactory extends SimpleWorkingCopyFactory cloneRepository(GitContext context, File target, String initialBranch) { - LOG.trace("clone repository {}", context.getRepository().getId()); - long start = System.nanoTime(); - try { - Repository clone = Git.cloneRepository() - .setURI(createScmTransportProtocolUri(context.getDirectory())) - .setDirectory(target) - .setBranch(initialBranch) - .call() - .getRepository(); + public WorkingCopyInitializer getInitializer(GitContext context) { + return (target, initialBranch) -> { + LOG.trace("clone repository {}", context.getRepository().getId()); + long start = System.nanoTime(); + try { + Repository clone = Git.cloneRepository() + .setURI(createScmTransportProtocolUri(context.getDirectory())) + .setDirectory(target) + .setBranch(initialBranch) + .call() + .getRepository(); - Ref head = clone.exactRef(Constants.HEAD); + Ref head = clone.exactRef(Constants.HEAD); - if (head == null || !head.isSymbolic() || (initialBranch != null && !head.getTarget().getName().endsWith(initialBranch))) { - throw notFound(entity("Branch", initialBranch).in(context.getRepository())); + if (head == null || !head.isSymbolic() || (initialBranch != null && !head.getTarget().getName().endsWith(initialBranch))) { + throw notFound(entity("Branch", initialBranch).in(context.getRepository())); + } + + return new ParentAndClone<>(null, clone, target); + } catch (GitAPIException | IOException e) { + throw new InternalRepositoryException(context.getRepository(), "could not clone working copy of repository", e); + } finally { + long end = System.nanoTime(); + long duration = end - start; + LOG.trace("took {} ns to clone repository {}", duration, context.getRepository().getId()); } - - return new ParentAndClone<>(null, clone, target); - } catch (GitAPIException | IOException e) { - throw new InternalRepositoryException(context.getRepository(), "could not clone working copy of repository", e); - } finally { - long end = System.nanoTime(); - long duration = end - start; - LOG.trace("took {} ns to clone repository {}", duration, context.getRepository().getId()); - } + }; } @Override - protected ParentAndClone reclaimRepository(GitContext context, File target, String initialBranch) throws ReclaimFailedException { - LOG.trace("reclaim repository {}", context.getRepository().getId()); - long start = System.nanoTime(); - Repository repo = openTarget(target); - try (Git git = Git.open(target)) { - git.reset().setMode(ResetCommand.ResetType.HARD).call(); - git.clean().setForce(true).setCleanDirectories(true).call(); - git.fetch().call(); - git.checkout().setForced(true).setName("origin/" + initialBranch).call(); - git.branchDelete().setBranchNames(initialBranch).setForce(true).call(); - git.checkout().setName(initialBranch).setCreateBranch(true).call(); - return new ParentAndClone<>(null, repo, target); - } catch (GitAPIException | IOException e) { - throw new ReclaimFailedException(e); - } finally { - long end = System.nanoTime(); - long duration = end - start; - LOG.trace("took {} ns to reclaim repository {}\n", duration, context.getRepository().getId()); - } + protected WorkingCopyReclaimer getReclaimer(GitContext context) { + return (target, initialBranch) -> { + LOG.trace("reclaim repository {}", context.getRepository().getId()); + long start = System.nanoTime(); + Repository repo = openTarget(target); + try (Git git = Git.open(target)) { + git.reset().setMode(ResetCommand.ResetType.HARD).call(); + git.clean().setForce(true).setCleanDirectories(true).call(); + git.fetch().call(); + git.checkout().setForced(true).setName("origin/" + initialBranch).call(); + git.branchDelete().setBranchNames(initialBranch).setForce(true).call(); + git.checkout().setName(initialBranch).setCreateBranch(true).call(); + return new ParentAndClone<>(null, repo, target); + } catch (GitAPIException | IOException e) { + throw new ReclaimFailedException(e); + } finally { + long end = System.nanoTime(); + long duration = end - start; + LOG.trace("took {} ns to reclaim repository {}\n", duration, context.getRepository().getId()); + } + }; } private Repository openTarget(File target) throws ReclaimFailedException { diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactoryTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactoryTest.java index 0b2ba55d95..93c1c1425b 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactoryTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactoryTest.java @@ -142,7 +142,7 @@ public class SimpleGitWorkingCopyFactoryTest extends AbstractGitCommandTestBase SimpleGitWorkingCopyFactory factory = new SimpleGitWorkingCopyFactory(new NoneCachingWorkingCopyPool(workdirProvider)); File workdir = createExistingClone(factory); - factory.reclaimRepository(createContext(), workdir, "master"); + factory.getReclaimer(createContext()).reclaim(workdir, "master"); assertBranchCheckedOutAndClean(workdir, "master"); } @@ -152,7 +152,7 @@ public class SimpleGitWorkingCopyFactoryTest extends AbstractGitCommandTestBase SimpleGitWorkingCopyFactory factory = new SimpleGitWorkingCopyFactory(new NoneCachingWorkingCopyPool(workdirProvider)); File workdir = createExistingClone(factory); - factory.reclaimRepository(createContext(), workdir, "test-branch"); + factory.getReclaimer(createContext()).reclaim(workdir, "test-branch"); assertBranchCheckedOutAndClean(workdir, "test-branch"); } @@ -163,7 +163,7 @@ public class SimpleGitWorkingCopyFactoryTest extends AbstractGitCommandTestBase File workdir = createExistingClone(factory); Git.open(workdir).rm().addFilepattern("a.txt").call(); - factory.reclaimRepository(createContext(), workdir, "master"); + factory.getReclaimer(createContext()).reclaim(workdir, "master"); assertBranchCheckedOutAndClean(workdir, "master"); } @@ -174,7 +174,7 @@ public class SimpleGitWorkingCopyFactoryTest extends AbstractGitCommandTestBase File workdir = createExistingClone(factory); Files.delete(workdir.toPath().resolve("a.txt")); - factory.reclaimRepository(createContext(), workdir, "master"); + factory.getReclaimer(createContext()).reclaim(workdir, "master"); assertBranchCheckedOutAndClean(workdir, "master"); } @@ -187,7 +187,7 @@ public class SimpleGitWorkingCopyFactoryTest extends AbstractGitCommandTestBase Files.createDirectories(newDirectory); Files.createFile(newDirectory.resolve("newFile")); - factory.reclaimRepository(createContext(), workdir, "master"); + factory.getReclaimer(createContext()).reclaim(workdir, "master"); assertBranchCheckedOutAndClean(workdir, "master"); } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactory.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactory.java index 170d57b421..51ae48716f 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactory.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactory.java @@ -41,6 +41,7 @@ import sonia.scm.web.HgRepositoryEnvironmentBuilder; import javax.inject.Inject; import javax.inject.Provider; +import javax.xml.stream.events.StartDocument; import java.io.File; import java.io.IOException; import java.util.Map; @@ -56,21 +57,23 @@ public class SimpleHgWorkingCopyFactory extends SimpleWorkingCopyFactory cloneRepository(HgCommandContext context, File target, String initialBranch) throws WorkingCopyFailedException { - Repository centralRepository = openCentral(context); - CloneCommand cloneCommand = CloneCommandFlags.on(centralRepository); - if (initialBranch != null) { - cloneCommand.updaterev(initialBranch); - } - try { - cloneCommand.execute(target.getAbsolutePath()); - } catch (IOException e) { - throw new WorkingCopyFailedException(e); - } + public WorkingCopyInitializer getInitializer(HgCommandContext context) { + return (target, initialBranch) -> { + Repository centralRepository = openCentral(context); + CloneCommand cloneCommand = CloneCommandFlags.on(centralRepository); + if (initialBranch != null) { + cloneCommand.updaterev(initialBranch); + } + try { + cloneCommand.execute(target.getAbsolutePath()); + } catch (IOException e) { + throw new WorkingCopyFailedException(e); + } - BaseRepository clone = Repository.open(target); + BaseRepository clone = Repository.open(target); - return new ParentAndClone<>(centralRepository, clone, target); + return new ParentAndClone<>(centralRepository, clone, target); + }; } public Repository openCentral(HgCommandContext context) { @@ -80,18 +83,20 @@ public class SimpleHgWorkingCopyFactory extends SimpleWorkingCopyFactory reclaimRepository(HgCommandContext context, File target, String initialBranch) throws ReclaimFailedException { - Repository centralRepository = openCentral(context); - try { - BaseRepository clone = Repository.open(target); - for (String unknown : StatusCommand.on(clone).execute().getUnknown()) { - delete(clone.getDirectory(), unknown); + protected WorkingCopyReclaimer getReclaimer(HgCommandContext context) { + return (target, initialBranch) -> { + Repository centralRepository = openCentral(context); + try { + BaseRepository clone = Repository.open(target); + for (String unknown : StatusCommand.on(clone).execute().getUnknown()) { + delete(clone.getDirectory(), unknown); + } + UpdateCommand.on(clone).rev(initialBranch).clean().execute(); + return new ParentAndClone<>(centralRepository, clone, target); + } catch (ExecutionException | IOException e) { + throw new ReclaimFailedException(e); } - UpdateCommand.on(clone).rev(initialBranch).clean().execute(); - return new ParentAndClone<>(centralRepository, clone, target); - } catch (ExecutionException | IOException e) { - throw new ReclaimFailedException(e); - } + }; } private void delete(File directory, String unknownFile) throws IOException { diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactory.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactory.java index 9b419d1eb6..5a59fd7dba 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactory.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactory.java @@ -50,41 +50,44 @@ public class SimpleSvnWorkingCopyFactory extends SimpleWorkingCopyFactory cloneRepository(SvnContext context, File workingCopy, String initialBranch) { + protected WorkingCopyInitializer getInitializer(SvnContext context) { + return (workingCopy, initialBranch) -> { + final SvnOperationFactory svnOperationFactory = new SvnOperationFactory(); - final SvnOperationFactory svnOperationFactory = new SvnOperationFactory(); + SVNURL source; + try { + source = SVNURL.fromFile(context.getDirectory()); + } catch (SVNException ex) { + throw new InternalRepositoryException(context.getRepository(), "error creating svn url from central directory", ex); + } - SVNURL source; - try { - source = SVNURL.fromFile(context.getDirectory()); - } catch (SVNException ex) { - throw new InternalRepositoryException(context.getRepository(), "error creating svn url from central directory", ex); - } + try { + final SvnCheckout checkout = svnOperationFactory.createCheckout(); + checkout.setSingleTarget(SvnTarget.fromFile(workingCopy)); + checkout.setSource(SvnTarget.fromURL(source)); + checkout.run(); + } catch (SVNException ex) { + throw new InternalRepositoryException(context.getRepository(), "error running svn checkout", ex); + } finally { + svnOperationFactory.dispose(); + } - try { - final SvnCheckout checkout = svnOperationFactory.createCheckout(); - checkout.setSingleTarget(SvnTarget.fromFile(workingCopy)); - checkout.setSource(SvnTarget.fromURL(source)); - checkout.run(); - } catch (SVNException ex) { - throw new InternalRepositoryException(context.getRepository(), "error running svn checkout", ex); - } finally { - svnOperationFactory.dispose(); - } - - return new ParentAndClone<>(context.getDirectory(), workingCopy, workingCopy); + return new ParentAndClone<>(context.getDirectory(), workingCopy, workingCopy); + }; } @Override - protected ParentAndClone reclaimRepository(SvnContext context, File target, String initialBranch) throws ReclaimFailedException { - SVNClientManager clientManager = SVNClientManager.newInstance(); - try { - clientManager.getWCClient().doCleanup(target); - clientManager.getUpdateClient().doUpdate(target, SVNRevision.HEAD, SVNDepth.fromRecurse(true), false, false); - } catch (SVNException e) { - throw new ReclaimFailedException(e); - } - return new ParentAndClone<>(context.getDirectory(), target, target); + protected WorkingCopyReclaimer getReclaimer(SvnContext context) { + return (target, initialBranch) -> { + SVNClientManager clientManager = SVNClientManager.newInstance(); + try { + clientManager.getWCClient().doCleanup(target); + clientManager.getUpdateClient().doUpdate(target, SVNRevision.HEAD, SVNDepth.fromRecurse(true), false, false); + } catch (SVNException e) { + throw new ReclaimFailedException(e); + } + return new ParentAndClone<>(context.getDirectory(), target, target); + }; } @Override From b40861534ced6f8975e89ea394200fddc2419b87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Sun, 10 May 2020 21:56:43 +0200 Subject: [PATCH 17/29] Extract classes --- .../spi/GitWorkingCopyInitializer.java | 84 +++++++++++++++++++ .../spi/GitWorkingCopyReclaimer.java | 79 +++++++++++++++++ .../spi/SimpleGitWorkingCopyFactory.java | 69 +-------------- 3 files changed, 166 insertions(+), 66 deletions(-) create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitWorkingCopyInitializer.java create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitWorkingCopyReclaimer.java diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitWorkingCopyInitializer.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitWorkingCopyInitializer.java new file mode 100644 index 0000000000..02c735a42c --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitWorkingCopyInitializer.java @@ -0,0 +1,84 @@ +/* + * 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.repository.spi; + +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.Repository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import sonia.scm.repository.InternalRepositoryException; +import sonia.scm.repository.work.SimpleWorkingCopyFactory; +import sonia.scm.repository.work.WorkingCopyFailedException; +import sonia.scm.repository.work.WorkingCopyPool; + +import java.io.File; +import java.io.IOException; + +import static sonia.scm.ContextEntry.ContextBuilder.entity; +import static sonia.scm.NotFoundException.notFound; + +class GitWorkingCopyInitializer implements SimpleWorkingCopyFactory.WorkingCopyInitializer { + + private static final Logger LOG = LoggerFactory.getLogger(GitWorkingCopyInitializer.class); + + private final SimpleGitWorkingCopyFactory simpleGitWorkingCopyFactory; + private final GitContext context; + + public GitWorkingCopyInitializer(SimpleGitWorkingCopyFactory simpleGitWorkingCopyFactory, GitContext context) { + this.simpleGitWorkingCopyFactory = simpleGitWorkingCopyFactory; + this.context = context; + } + + @Override + public WorkingCopyPool.ParentAndClone initialize(File target, String initialBranch) throws WorkingCopyFailedException { + LOG.trace("clone repository {}", context.getRepository().getId()); + long start = System.nanoTime(); + try { + Repository clone = Git.cloneRepository() + .setURI(simpleGitWorkingCopyFactory.createScmTransportProtocolUri(context.getDirectory())) + .setDirectory(target) + .setBranch(initialBranch) + .call() + .getRepository(); + + Ref head = clone.exactRef(Constants.HEAD); + + if (head == null || !head.isSymbolic() || (initialBranch != null && !head.getTarget().getName().endsWith(initialBranch))) { + throw notFound(entity("Branch", initialBranch).in(context.getRepository())); + } + + return new WorkingCopyPool.ParentAndClone<>(null, clone, target); + } catch (GitAPIException | IOException e) { + throw new InternalRepositoryException(context.getRepository(), "could not clone working copy of repository", e); + } finally { + long end = System.nanoTime(); + long duration = end - start; + LOG.trace("took {} ns to clone repository {}", duration, context.getRepository().getId()); + } + } +} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitWorkingCopyReclaimer.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitWorkingCopyReclaimer.java new file mode 100644 index 0000000000..95d6b8a09b --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitWorkingCopyReclaimer.java @@ -0,0 +1,79 @@ +/* + * 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.repository.spi; + +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.ResetCommand; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.lib.Repository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import sonia.scm.repository.GitUtil; +import sonia.scm.repository.work.SimpleWorkingCopyFactory; +import sonia.scm.repository.work.WorkingCopyPool; + +import java.io.File; +import java.io.IOException; + +class GitWorkingCopyReclaimer implements SimpleWorkingCopyFactory.WorkingCopyReclaimer { + + private static final Logger LOG = LoggerFactory.getLogger(GitWorkingCopyReclaimer.class); + + private final GitContext context; + + public GitWorkingCopyReclaimer(GitContext context) { + this.context = context; + } + + @Override + public WorkingCopyPool.ParentAndClone reclaim(File target, String initialBranch) throws SimpleWorkingCopyFactory.ReclaimFailedException { + LOG.trace("reclaim repository {}", context.getRepository().getId()); + long start = System.nanoTime(); + Repository repo = openTarget(target); + try (Git git = Git.open(target)) { + git.reset().setMode(ResetCommand.ResetType.HARD).call(); + git.clean().setForce(true).setCleanDirectories(true).call(); + git.fetch().call(); + git.checkout().setForced(true).setName("origin/" + initialBranch).call(); + git.branchDelete().setBranchNames(initialBranch).setForce(true).call(); + git.checkout().setName(initialBranch).setCreateBranch(true).call(); + return new WorkingCopyPool.ParentAndClone<>(null, repo, target); + } catch (GitAPIException | IOException e) { + throw new SimpleWorkingCopyFactory.ReclaimFailedException(e); + } finally { + long end = System.nanoTime(); + long duration = end - start; + LOG.trace("took {} ns to reclaim repository {}\n", duration, context.getRepository().getId()); + } + } + + private Repository openTarget(File target) throws SimpleWorkingCopyFactory.ReclaimFailedException { + try { + return GitUtil.open(target); + } catch (IOException e) { + throw new SimpleWorkingCopyFactory.ReclaimFailedException(e); + } + } +} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactory.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactory.java index 5ce8f757b8..2de4ff92c0 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactory.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactory.java @@ -24,34 +24,22 @@ package sonia.scm.repository.spi; -import org.eclipse.jgit.api.Git; -import org.eclipse.jgit.api.ResetCommand; -import org.eclipse.jgit.api.errors.GitAPIException; -import org.eclipse.jgit.lib.Constants; -import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.transport.ScmTransportProtocol; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import sonia.scm.repository.GitUtil; import sonia.scm.repository.GitWorkingCopyFactory; -import sonia.scm.repository.InternalRepositoryException; import sonia.scm.repository.work.WorkingCopyPool; import sonia.scm.repository.work.SimpleWorkingCopyFactory; -import sonia.scm.repository.work.WorkingCopyPool.ParentAndClone; import sonia.scm.util.SystemUtil; import javax.inject.Inject; import java.io.File; -import java.io.IOException; import static sonia.scm.ContextEntry.ContextBuilder.entity; -import static sonia.scm.NotFoundException.notFound; public class SimpleGitWorkingCopyFactory extends SimpleWorkingCopyFactory implements GitWorkingCopyFactory { - private static final Logger LOG = LoggerFactory.getLogger(SimpleGitWorkingCopyFactory.class); - @Inject public SimpleGitWorkingCopyFactory(WorkingCopyPool workdirProvider) { super(workdirProvider); @@ -59,64 +47,12 @@ public class SimpleGitWorkingCopyFactory extends SimpleWorkingCopyFactory getInitializer(GitContext context) { - return (target, initialBranch) -> { - LOG.trace("clone repository {}", context.getRepository().getId()); - long start = System.nanoTime(); - try { - Repository clone = Git.cloneRepository() - .setURI(createScmTransportProtocolUri(context.getDirectory())) - .setDirectory(target) - .setBranch(initialBranch) - .call() - .getRepository(); - - Ref head = clone.exactRef(Constants.HEAD); - - if (head == null || !head.isSymbolic() || (initialBranch != null && !head.getTarget().getName().endsWith(initialBranch))) { - throw notFound(entity("Branch", initialBranch).in(context.getRepository())); - } - - return new ParentAndClone<>(null, clone, target); - } catch (GitAPIException | IOException e) { - throw new InternalRepositoryException(context.getRepository(), "could not clone working copy of repository", e); - } finally { - long end = System.nanoTime(); - long duration = end - start; - LOG.trace("took {} ns to clone repository {}", duration, context.getRepository().getId()); - } - }; + return new GitWorkingCopyInitializer(this, context); } @Override protected WorkingCopyReclaimer getReclaimer(GitContext context) { - return (target, initialBranch) -> { - LOG.trace("reclaim repository {}", context.getRepository().getId()); - long start = System.nanoTime(); - Repository repo = openTarget(target); - try (Git git = Git.open(target)) { - git.reset().setMode(ResetCommand.ResetType.HARD).call(); - git.clean().setForce(true).setCleanDirectories(true).call(); - git.fetch().call(); - git.checkout().setForced(true).setName("origin/" + initialBranch).call(); - git.branchDelete().setBranchNames(initialBranch).setForce(true).call(); - git.checkout().setName(initialBranch).setCreateBranch(true).call(); - return new ParentAndClone<>(null, repo, target); - } catch (GitAPIException | IOException e) { - throw new ReclaimFailedException(e); - } finally { - long end = System.nanoTime(); - long duration = end - start; - LOG.trace("took {} ns to reclaim repository {}\n", duration, context.getRepository().getId()); - } - }; - } - - private Repository openTarget(File target) throws ReclaimFailedException { - try { - return GitUtil.open(target); - } catch (IOException e) { - throw new ReclaimFailedException(e); - } + return new GitWorkingCopyReclaimer(context); } String createScmTransportProtocolUri(File bareRepository) { @@ -142,4 +78,5 @@ public class SimpleGitWorkingCopyFactory extends SimpleWorkingCopyFactory Date: Mon, 11 May 2020 21:43:51 +0200 Subject: [PATCH 18/29] Cleanup svn on reclaim --- .../spi/SimpleSvnWorkingCopyFactory.java | 48 +------------ .../spi/SvnWorkingCopyInitializer.java | 70 +++++++++++++++++++ .../spi/SvnWorkingCopyReclaimer.java | 56 +++++++++++++++ .../spi/SimpleSvnWorkingCopyFactoryTest.java | 40 +++++++++-- 4 files changed, 163 insertions(+), 51 deletions(-) create mode 100644 scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnWorkingCopyInitializer.java create mode 100644 scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnWorkingCopyReclaimer.java diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactory.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactory.java index 5a59fd7dba..6156ad6cf5 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactory.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactory.java @@ -24,20 +24,9 @@ package sonia.scm.repository.spi; -import org.tmatesoft.svn.core.SVNDepth; -import org.tmatesoft.svn.core.SVNException; -import org.tmatesoft.svn.core.SVNURL; -import org.tmatesoft.svn.core.wc.SVNClientManager; -import org.tmatesoft.svn.core.wc.SVNRevision; -import org.tmatesoft.svn.core.wc2.SvnCheckout; -import org.tmatesoft.svn.core.wc2.SvnOperationFactory; -import org.tmatesoft.svn.core.wc2.SvnTarget; -import sonia.scm.repository.InternalRepositoryException; -import sonia.scm.repository.Repository; import sonia.scm.repository.SvnWorkingCopyFactory; import sonia.scm.repository.work.WorkingCopyPool; import sonia.scm.repository.work.SimpleWorkingCopyFactory; -import sonia.scm.repository.work.WorkingCopyPool.ParentAndClone; import javax.inject.Inject; import java.io.File; @@ -50,44 +39,13 @@ public class SimpleSvnWorkingCopyFactory extends SimpleWorkingCopyFactory { - final SvnOperationFactory svnOperationFactory = new SvnOperationFactory(); - - SVNURL source; - try { - source = SVNURL.fromFile(context.getDirectory()); - } catch (SVNException ex) { - throw new InternalRepositoryException(context.getRepository(), "error creating svn url from central directory", ex); - } - - try { - final SvnCheckout checkout = svnOperationFactory.createCheckout(); - checkout.setSingleTarget(SvnTarget.fromFile(workingCopy)); - checkout.setSource(SvnTarget.fromURL(source)); - checkout.run(); - } catch (SVNException ex) { - throw new InternalRepositoryException(context.getRepository(), "error running svn checkout", ex); - } finally { - svnOperationFactory.dispose(); - } - - return new ParentAndClone<>(context.getDirectory(), workingCopy, workingCopy); - }; + protected WorkingCopyInitializer getInitializer(SvnContext context) { + return new SvnWorkingCopyInitializer(context); } @Override protected WorkingCopyReclaimer getReclaimer(SvnContext context) { - return (target, initialBranch) -> { - SVNClientManager clientManager = SVNClientManager.newInstance(); - try { - clientManager.getWCClient().doCleanup(target); - clientManager.getUpdateClient().doUpdate(target, SVNRevision.HEAD, SVNDepth.fromRecurse(true), false, false); - } catch (SVNException e) { - throw new ReclaimFailedException(e); - } - return new ParentAndClone<>(context.getDirectory(), target, target); - }; + return new SvnWorkingCopyReclaimer(context); } @Override diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnWorkingCopyInitializer.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnWorkingCopyInitializer.java new file mode 100644 index 0000000000..06a2edba02 --- /dev/null +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnWorkingCopyInitializer.java @@ -0,0 +1,70 @@ +/* + * 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.repository.spi; + +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.SVNURL; +import org.tmatesoft.svn.core.wc2.SvnCheckout; +import org.tmatesoft.svn.core.wc2.SvnOperationFactory; +import org.tmatesoft.svn.core.wc2.SvnTarget; +import sonia.scm.repository.InternalRepositoryException; +import sonia.scm.repository.work.SimpleWorkingCopyFactory; +import sonia.scm.repository.work.WorkingCopyFailedException; +import sonia.scm.repository.work.WorkingCopyPool; + +import java.io.File; + +class SvnWorkingCopyInitializer implements SimpleWorkingCopyFactory.WorkingCopyInitializer { + private final SvnContext context; + + public SvnWorkingCopyInitializer(SvnContext context) { + this.context = context; + } + + @Override + public WorkingCopyPool.ParentAndClone initialize(File workingCopy, String initialBranch) throws WorkingCopyFailedException { + final SvnOperationFactory svnOperationFactory = new SvnOperationFactory(); + + SVNURL source; + try { + source = SVNURL.fromFile(context.getDirectory()); + } catch (SVNException ex) { + throw new InternalRepositoryException(context.getRepository(), "error creating svn url from central directory", ex); + } + + try { + final SvnCheckout checkout = svnOperationFactory.createCheckout(); + checkout.setSingleTarget(SvnTarget.fromFile(workingCopy)); + checkout.setSource(SvnTarget.fromURL(source)); + checkout.run(); + } catch (SVNException ex) { + throw new InternalRepositoryException(context.getRepository(), "error running svn checkout", ex); + } finally { + svnOperationFactory.dispose(); + } + + return new WorkingCopyPool.ParentAndClone<>(context.getDirectory(), workingCopy, workingCopy); + } +} diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnWorkingCopyReclaimer.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnWorkingCopyReclaimer.java new file mode 100644 index 0000000000..9ed5c6006f --- /dev/null +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnWorkingCopyReclaimer.java @@ -0,0 +1,56 @@ +/* + * 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.repository.spi; + +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.wc.SVNClientManager; +import org.tmatesoft.svn.core.wc.SVNRevision; +import sonia.scm.repository.work.SimpleWorkingCopyFactory; +import sonia.scm.repository.work.WorkingCopyPool; + +import java.io.File; + +import static org.tmatesoft.svn.core.SVNDepth.INFINITY; + +class SvnWorkingCopyReclaimer implements SimpleWorkingCopyFactory.WorkingCopyReclaimer { + private final SvnContext context; + + public SvnWorkingCopyReclaimer(SvnContext context) { + this.context = context; + } + + @Override + public WorkingCopyPool.ParentAndClone reclaim(File target, String initialBranch) throws SimpleWorkingCopyFactory.ReclaimFailedException { + SVNClientManager clientManager = SVNClientManager.newInstance(); + try { + clientManager.getWCClient().doRevert(new File[] {target}, INFINITY, null); + clientManager.getWCClient().doCleanup(target, true, true, true, true, true, false); + clientManager.getUpdateClient().doUpdate(target, SVNRevision.HEAD, INFINITY, false, false); + } catch (SVNException e) { + throw new SimpleWorkingCopyFactory.ReclaimFailedException(e); + } + return new WorkingCopyPool.ParentAndClone<>(context.getDirectory(), target, target); + } +} diff --git a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactoryTest.java b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactoryTest.java index 9cac5f205d..d5fc3c70fe 100644 --- a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactoryTest.java +++ b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactoryTest.java @@ -29,7 +29,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.tmatesoft.svn.core.SVNException; -import sonia.scm.repository.Repository; +import sonia.scm.repository.work.CachingAllWorkingCopyPool; import sonia.scm.repository.work.NoneCachingWorkingCopyPool; import sonia.scm.repository.work.WorkdirProvider; import sonia.scm.repository.work.WorkingCopy; @@ -87,16 +87,44 @@ public class SimpleSvnWorkingCopyFactoryTest extends AbstractSvnCommandTestBase try (WorkingCopy workingCopy = factory.createWorkingCopy(createContext(), null)) { directory = workingCopy.getDirectory(); workingRepository = workingCopy.getWorkingRepository(); - } + assertThat(directory).doesNotExist(); assertThat(workingRepository).doesNotExist(); } @Test - public void shouldReturnRepository() { - SimpleSvnWorkingCopyFactory factory = new SimpleSvnWorkingCopyFactory(new NoneCachingWorkingCopyPool(workdirProvider)); - Repository scmRepository = createContext().getRepository(); - assertThat(scmRepository).isSameAs(repository); + public void shouldDeleteUntrackedFileOnReclaim() throws IOException { + SimpleSvnWorkingCopyFactory factory = new SimpleSvnWorkingCopyFactory(new CachingAllWorkingCopyPool(workdirProvider)); + + WorkingCopy workingCopy = factory.createWorkingCopy(createContext(), null); + File directory = workingCopy.getWorkingRepository(); + File untracked = new File(directory, "untracked"); + untracked.createNewFile(); + + workingCopy.close(); + assertThat(untracked).exists(); + + workingCopy = factory.createWorkingCopy(createContext(), null); + + assertThat(workingCopy.getWorkingRepository()).isEqualTo(directory); + assertThat(untracked).doesNotExist(); + } + + @Test + public void shouldRestoreDeletedFileOnReclaim() throws IOException { + SimpleSvnWorkingCopyFactory factory = new SimpleSvnWorkingCopyFactory(new CachingAllWorkingCopyPool(workdirProvider)); + + WorkingCopy workingCopy = factory.createWorkingCopy(createContext(), null); + File directory = workingCopy.getWorkingRepository(); + File a_txt = new File(directory, "a.txt"); + a_txt.delete(); + workingCopy.close(); + assertThat(a_txt).doesNotExist(); + + workingCopy = factory.createWorkingCopy(createContext(), null); + + assertThat(workingCopy.getWorkingRepository()).isEqualTo(directory); + assertThat(a_txt).exists(); } } From 3c808bf17112c4636b1522d19f99cc63921803ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Thu, 14 May 2020 21:27:35 +0200 Subject: [PATCH 19/29] Use existing RepositoryProvider --- .../work/CachingAllWorkingCopyPool.java | 15 +++++++-------- .../work/NoneCachingWorkingCopyPool.java | 5 ++--- .../repository/work/SimpleWorkingCopyFactory.java | 5 ++--- .../scm/repository/work/WorkingCopyContext.java | 5 ++--- .../scm/repository/work/WorkingCopyPool.java | 5 ++--- .../work/CachingAllWorkingCopyPoolTest.java | 5 ++--- .../work/SimpleWorkingCopyFactoryTest.java | 6 +++--- .../java/sonia/scm/repository/spi/GitContext.java | 9 ++------- .../scm/repository/spi/HgCommandContext.java | 10 ++++------ .../spi/SimpleHgWorkingCopyFactory.java | 3 +-- .../java/sonia/scm/repository/spi/SvnContext.java | 10 ++-------- 11 files changed, 29 insertions(+), 49 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/repository/work/CachingAllWorkingCopyPool.java b/scm-core/src/main/java/sonia/scm/repository/work/CachingAllWorkingCopyPool.java index 3cf5074e74..a91bf3319f 100644 --- a/scm-core/src/main/java/sonia/scm/repository/work/CachingAllWorkingCopyPool.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/CachingAllWorkingCopyPool.java @@ -28,14 +28,13 @@ import com.google.common.base.Stopwatch; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sonia.scm.repository.InternalRepositoryException; -import sonia.scm.repository.Repository; +import sonia.scm.repository.RepositoryProvider; import sonia.scm.util.IOUtil; import javax.inject.Inject; import java.io.File; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Supplier; public class CachingAllWorkingCopyPool implements WorkingCopyPool { @@ -51,7 +50,7 @@ public class CachingAllWorkingCopyPool implements WorkingCopyPool { } @Override - public > ParentAndClone getWorkingCopy(WorkingCopyContext workingCopyContext) { + public ParentAndClone getWorkingCopy(WorkingCopyContext workingCopyContext) { String id = workingCopyContext.getScmRepository().getId(); File existingWorkdir = workdirs.remove(id); if (existingWorkdir != null) { @@ -66,13 +65,13 @@ public class CachingAllWorkingCopyPool implements WorkingCopyPool { } } try { - return createNewWorkdir(workingCopyContext); + return createNewWorkingCopy(workingCopyContext); } catch (WorkingCopyFailedException e) { throw new InternalRepositoryException(workingCopyContext.getScmRepository(), "failed to create working copy", e); } } - private ParentAndClone createNewWorkdir(WorkingCopyContext workingCopyContext) throws WorkingCopyFailedException { + private ParentAndClone createNewWorkingCopy(WorkingCopyContext workingCopyContext) throws WorkingCopyFailedException { Stopwatch stopwatch = Stopwatch.createStarted(); File newWorkdir = workdirProvider.createNewWorkdir(); SimpleWorkingCopyFactory.WorkingCopyInitializer initializer = workingCopyContext.getInitializer(); @@ -96,9 +95,9 @@ public class CachingAllWorkingCopyPool implements WorkingCopyPool { workdirs.clear(); } - private void deleteWorkdir(File existingWorkdir) { - if (existingWorkdir.exists()) { - IOUtil.deleteSilently(existingWorkdir); + private void deleteWorkdir(File workdir) { + if (workdir.exists()) { + IOUtil.deleteSilently(workdir); } } } diff --git a/scm-core/src/main/java/sonia/scm/repository/work/NoneCachingWorkingCopyPool.java b/scm-core/src/main/java/sonia/scm/repository/work/NoneCachingWorkingCopyPool.java index ccc3ddc658..9f99790c99 100644 --- a/scm-core/src/main/java/sonia/scm/repository/work/NoneCachingWorkingCopyPool.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/NoneCachingWorkingCopyPool.java @@ -24,12 +24,11 @@ package sonia.scm.repository.work; -import sonia.scm.repository.Repository; +import sonia.scm.repository.RepositoryProvider; import sonia.scm.util.IOUtil; import javax.inject.Inject; import java.io.File; -import java.util.function.Supplier; public class NoneCachingWorkingCopyPool implements WorkingCopyPool { @@ -41,7 +40,7 @@ public class NoneCachingWorkingCopyPool implements WorkingCopyPool { } @Override - public > ParentAndClone getWorkingCopy(WorkingCopyContext context) throws WorkingCopyFailedException { + public ParentAndClone getWorkingCopy(WorkingCopyContext context) throws WorkingCopyFailedException { return context.getInitializer().initialize(workdirProvider.createNewWorkdir(), context.getRequestedBranch()); } diff --git a/scm-core/src/main/java/sonia/scm/repository/work/SimpleWorkingCopyFactory.java b/scm-core/src/main/java/sonia/scm/repository/work/SimpleWorkingCopyFactory.java index cb6f233b1c..42bea961ad 100644 --- a/scm-core/src/main/java/sonia/scm/repository/work/SimpleWorkingCopyFactory.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/SimpleWorkingCopyFactory.java @@ -27,12 +27,11 @@ package sonia.scm.repository.work; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sonia.scm.repository.InternalRepositoryException; -import sonia.scm.repository.Repository; +import sonia.scm.repository.RepositoryProvider; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import java.io.File; -import java.util.function.Supplier; /** * This class is responsible to govern the creation, the reuse and the destruction @@ -180,7 +179,7 @@ SimpleGitWorkingCopyFactory->SimpleGitWorkingCopyFactory:closeRepository SimpleGitWorkingCopyFactory->WorkingCopyPool:contextClosed @enduml */ -public abstract class SimpleWorkingCopyFactory> implements WorkingCopyFactory, ServletContextListener { +public abstract class SimpleWorkingCopyFactory implements WorkingCopyFactory, ServletContextListener { private static final Logger LOG = LoggerFactory.getLogger(SimpleWorkingCopyFactory.class); diff --git a/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyContext.java b/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyContext.java index 86fda237a3..e4574bc454 100644 --- a/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyContext.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyContext.java @@ -25,10 +25,9 @@ package sonia.scm.repository.work; import sonia.scm.repository.Repository; +import sonia.scm.repository.RepositoryProvider; -import java.util.function.Supplier; - -public class WorkingCopyContext> { +public class WorkingCopyContext { private final String requestedBranch; private final C context; private final SimpleWorkingCopyFactory.WorkingCopyInitializer initializer; diff --git a/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyPool.java b/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyPool.java index 4f261a5601..e5bbfbe4b1 100644 --- a/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyPool.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyPool.java @@ -24,13 +24,12 @@ package sonia.scm.repository.work; -import sonia.scm.repository.Repository; +import sonia.scm.repository.RepositoryProvider; import java.io.File; -import java.util.function.Supplier; public interface WorkingCopyPool { - > ParentAndClone getWorkingCopy(WorkingCopyContext context) throws WorkingCopyFailedException; + ParentAndClone getWorkingCopy(WorkingCopyContext context) throws WorkingCopyFailedException; void contextClosed(WorkingCopyContext workingCopyContext, File workdir); diff --git a/scm-core/src/test/java/sonia/scm/repository/work/CachingAllWorkingCopyPoolTest.java b/scm-core/src/test/java/sonia/scm/repository/work/CachingAllWorkingCopyPoolTest.java index 102e4c2098..e80a9c346a 100644 --- a/scm-core/src/test/java/sonia/scm/repository/work/CachingAllWorkingCopyPoolTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/work/CachingAllWorkingCopyPoolTest.java @@ -32,14 +32,13 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import sonia.scm.repository.Repository; +import sonia.scm.repository.RepositoryProvider; import java.io.File; import java.nio.file.Path; -import java.util.function.Supplier; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -56,7 +55,7 @@ class CachingAllWorkingCopyPoolTest { CachingAllWorkingCopyPool cachingAllWorkingCopyPool; @Mock - WorkingCopyContext> workingCopyContext; + WorkingCopyContext workingCopyContext; @Mock SimpleWorkingCopyFactory.WorkingCopyInitializer initializer; @Mock diff --git a/scm-core/src/test/java/sonia/scm/repository/work/SimpleWorkingCopyFactoryTest.java b/scm-core/src/test/java/sonia/scm/repository/work/SimpleWorkingCopyFactoryTest.java index 158e8fbb72..00276fe83f 100644 --- a/scm-core/src/test/java/sonia/scm/repository/work/SimpleWorkingCopyFactoryTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/work/SimpleWorkingCopyFactoryTest.java @@ -29,12 +29,12 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import sonia.scm.repository.Repository; +import sonia.scm.repository.RepositoryProvider; import sonia.scm.util.IOUtil; import java.io.Closeable; import java.io.File; import java.io.IOException; -import java.util.function.Supplier; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; @@ -61,7 +61,7 @@ public class SimpleWorkingCopyFactoryTest { WorkdirProvider workdirProvider = new WorkdirProvider(temporaryFolder.newFolder()); WorkingCopyPool configurableTestWorkingCopyPool = new WorkingCopyPool() { @Override - public > ParentAndClone getWorkingCopy(WorkingCopyContext context) throws WorkingCopyFailedException { + public ParentAndClone getWorkingCopy(WorkingCopyContext context) throws WorkingCopyFailedException { workdir = workdirProvider.createNewWorkdir(); return context.getInitializer().initialize(workdir, context.getRequestedBranch()); } @@ -154,7 +154,7 @@ public class SimpleWorkingCopyFactoryTest { } } - private static class Context implements Supplier { + private static class Context implements RepositoryProvider { @Override public Repository get() { return REPOSITORY; diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitContext.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitContext.java index 3763e57939..c7f0327312 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitContext.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitContext.java @@ -24,28 +24,23 @@ package sonia.scm.repository.spi; -//~--- non-JDK imports -------------------------------------------------------- - import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import sonia.scm.api.v2.resources.GitRepositoryConfigStoreProvider; import sonia.scm.repository.GitRepositoryConfig; import sonia.scm.repository.GitUtil; import sonia.scm.repository.Repository; - -//~--- JDK imports ------------------------------------------------------------ +import sonia.scm.repository.RepositoryProvider; import java.io.Closeable; import java.io.File; import java.io.IOException; -import java.util.function.Supplier; /** * * @author Sebastian Sdorra */ -public class GitContext implements Closeable, Supplier +public class GitContext implements Closeable, RepositoryProvider { /** diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgCommandContext.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgCommandContext.java index 4c563a9b48..39181d3d67 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgCommandContext.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgCommandContext.java @@ -27,28 +27,26 @@ package sonia.scm.repository.spi; //~--- non-JDK imports -------------------------------------------------------- import com.aragost.javahg.Repository; - import com.google.common.base.Strings; - import sonia.scm.repository.HgConfig; import sonia.scm.repository.HgHookManager; import sonia.scm.repository.HgRepositoryHandler; +import sonia.scm.repository.RepositoryProvider; import sonia.scm.web.HgUtil; -//~--- JDK imports ------------------------------------------------------------ - import java.io.Closeable; import java.io.File; import java.io.IOException; import java.util.Map; import java.util.function.BiConsumer; -import java.util.function.Supplier; + +//~--- JDK imports ------------------------------------------------------------ /** * * @author Sebastian Sdorra */ -public class HgCommandContext implements Closeable, Supplier +public class HgCommandContext implements Closeable, RepositoryProvider { /** Field description */ diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactory.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactory.java index 51ae48716f..ae8a25426f 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactory.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactory.java @@ -32,16 +32,15 @@ import com.aragost.javahg.commands.PullCommand; import com.aragost.javahg.commands.StatusCommand; import com.aragost.javahg.commands.UpdateCommand; import com.aragost.javahg.commands.flags.CloneCommandFlags; +import sonia.scm.repository.work.SimpleWorkingCopyFactory; import sonia.scm.repository.work.WorkingCopyFailedException; import sonia.scm.repository.work.WorkingCopyPool; -import sonia.scm.repository.work.SimpleWorkingCopyFactory; import sonia.scm.repository.work.WorkingCopyPool.ParentAndClone; import sonia.scm.util.IOUtil; import sonia.scm.web.HgRepositoryEnvironmentBuilder; import javax.inject.Inject; import javax.inject.Provider; -import javax.xml.stream.events.StartDocument; import java.io.File; import java.io.IOException; import java.util.Map; diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnContext.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnContext.java index 87827c624b..639bf25e8a 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnContext.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnContext.java @@ -24,30 +24,24 @@ package sonia.scm.repository.spi; -//~--- non-JDK imports -------------------------------------------------------- - import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.io.SVNRepository; import org.tmatesoft.svn.core.io.SVNRepositoryFactory; - import sonia.scm.repository.Repository; +import sonia.scm.repository.RepositoryProvider; import sonia.scm.repository.SvnUtil; -//~--- JDK imports ------------------------------------------------------------ - import java.io.Closeable; import java.io.File; -import java.util.function.Supplier; /** * * @author Sebastian Sdorra */ -public class SvnContext implements Closeable, Supplier { +public class SvnContext implements Closeable, RepositoryProvider { private static final Logger LOG = LoggerFactory.getLogger(SvnContext.class); From d6b618f0eced79c59e414e0555e071a04060f094 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Thu, 14 May 2020 21:42:00 +0200 Subject: [PATCH 20/29] Remove superfluous exception class --- .../work/CachingAllWorkingCopyPool.java | 9 +---- .../work/NoneCachingWorkingCopyPool.java | 2 +- .../work/SimpleWorkingCopyFactory.java | 12 ++---- .../work/WorkingCopyFailedException.java | 39 ------------------- .../scm/repository/work/WorkingCopyPool.java | 2 +- .../work/CachingAllWorkingCopyPoolTest.java | 8 ++-- .../work/SimpleWorkingCopyFactoryTest.java | 2 +- .../spi/GitWorkingCopyInitializer.java | 3 +- .../spi/SimpleHgWorkingCopyFactory.java | 6 +-- .../spi/SvnWorkingCopyInitializer.java | 3 +- 10 files changed, 18 insertions(+), 68 deletions(-) delete mode 100644 scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyFailedException.java diff --git a/scm-core/src/main/java/sonia/scm/repository/work/CachingAllWorkingCopyPool.java b/scm-core/src/main/java/sonia/scm/repository/work/CachingAllWorkingCopyPool.java index a91bf3319f..bb64a82d88 100644 --- a/scm-core/src/main/java/sonia/scm/repository/work/CachingAllWorkingCopyPool.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/CachingAllWorkingCopyPool.java @@ -27,7 +27,6 @@ package sonia.scm.repository.work; import com.google.common.base.Stopwatch; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import sonia.scm.repository.InternalRepositoryException; import sonia.scm.repository.RepositoryProvider; import sonia.scm.util.IOUtil; @@ -64,14 +63,10 @@ public class CachingAllWorkingCopyPool implements WorkingCopyPool { deleteWorkdir(existingWorkdir); } } - try { - return createNewWorkingCopy(workingCopyContext); - } catch (WorkingCopyFailedException e) { - throw new InternalRepositoryException(workingCopyContext.getScmRepository(), "failed to create working copy", e); - } + return createNewWorkingCopy(workingCopyContext); } - private ParentAndClone createNewWorkingCopy(WorkingCopyContext workingCopyContext) throws WorkingCopyFailedException { + private ParentAndClone createNewWorkingCopy(WorkingCopyContext workingCopyContext) { Stopwatch stopwatch = Stopwatch.createStarted(); File newWorkdir = workdirProvider.createNewWorkdir(); SimpleWorkingCopyFactory.WorkingCopyInitializer initializer = workingCopyContext.getInitializer(); diff --git a/scm-core/src/main/java/sonia/scm/repository/work/NoneCachingWorkingCopyPool.java b/scm-core/src/main/java/sonia/scm/repository/work/NoneCachingWorkingCopyPool.java index 9f99790c99..630b36b470 100644 --- a/scm-core/src/main/java/sonia/scm/repository/work/NoneCachingWorkingCopyPool.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/NoneCachingWorkingCopyPool.java @@ -40,7 +40,7 @@ public class NoneCachingWorkingCopyPool implements WorkingCopyPool { } @Override - public ParentAndClone getWorkingCopy(WorkingCopyContext context) throws WorkingCopyFailedException { + public ParentAndClone getWorkingCopy(WorkingCopyContext context) { return context.getInitializer().initialize(workdirProvider.createNewWorkdir(), context.getRequestedBranch()); } diff --git a/scm-core/src/main/java/sonia/scm/repository/work/SimpleWorkingCopyFactory.java b/scm-core/src/main/java/sonia/scm/repository/work/SimpleWorkingCopyFactory.java index 42bea961ad..7e6a941871 100644 --- a/scm-core/src/main/java/sonia/scm/repository/work/SimpleWorkingCopyFactory.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/SimpleWorkingCopyFactory.java @@ -191,13 +191,9 @@ public abstract class SimpleWorkingCopyFactory createWorkingCopy(C repositoryContext, String initialBranch) { - try { - WorkingCopyContext workingCopyContext = createWorkingCopyContext(repositoryContext, initialBranch); - WorkingCopyPool.ParentAndClone parentAndClone = workingCopyPool.getWorkingCopy(workingCopyContext); - return new WorkingCopy<>(parentAndClone.getClone(), parentAndClone.getParent(), () -> this.close(workingCopyContext, parentAndClone), parentAndClone.getDirectory()); - } catch (WorkingCopyFailedException e) { - throw new InternalRepositoryException(repositoryContext.get(), "could not create working copy for repository in temporary directory", e); - } + WorkingCopyContext workingCopyContext = createWorkingCopyContext(repositoryContext, initialBranch); + WorkingCopyPool.ParentAndClone parentAndClone = workingCopyPool.getWorkingCopy(workingCopyContext); + return new WorkingCopy<>(parentAndClone.getClone(), parentAndClone.getParent(), () -> this.close(workingCopyContext, parentAndClone), parentAndClone.getDirectory()); } private WorkingCopyContext createWorkingCopyContext(C repositoryContext, String initialBranch) { @@ -239,7 +235,7 @@ public abstract class SimpleWorkingCopyFactory { - WorkingCopyPool.ParentAndClone initialize(File target, String initialBranch) throws WorkingCopyFailedException; + WorkingCopyPool.ParentAndClone initialize(File target, String initialBranch); } @FunctionalInterface diff --git a/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyFailedException.java b/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyFailedException.java deleted file mode 100644 index 985e348de7..0000000000 --- a/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyFailedException.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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.repository.work; - -public class WorkingCopyFailedException extends Exception { - public WorkingCopyFailedException(String message) { - super(message); - } - - public WorkingCopyFailedException(Throwable cause) { - super(cause); - } - - public WorkingCopyFailedException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyPool.java b/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyPool.java index e5bbfbe4b1..c389fe6bae 100644 --- a/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyPool.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyPool.java @@ -29,7 +29,7 @@ import sonia.scm.repository.RepositoryProvider; import java.io.File; public interface WorkingCopyPool { - ParentAndClone getWorkingCopy(WorkingCopyContext context) throws WorkingCopyFailedException; + ParentAndClone getWorkingCopy(WorkingCopyContext context); void contextClosed(WorkingCopyContext workingCopyContext, File workdir); diff --git a/scm-core/src/test/java/sonia/scm/repository/work/CachingAllWorkingCopyPoolTest.java b/scm-core/src/test/java/sonia/scm/repository/work/CachingAllWorkingCopyPoolTest.java index e80a9c346a..51ed82a01a 100644 --- a/scm-core/src/test/java/sonia/scm/repository/work/CachingAllWorkingCopyPoolTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/work/CachingAllWorkingCopyPoolTest.java @@ -62,7 +62,7 @@ class CachingAllWorkingCopyPoolTest { SimpleWorkingCopyFactory.WorkingCopyReclaimer reclaimer; @BeforeEach - void initContext() throws SimpleWorkingCopyFactory.ReclaimFailedException, WorkingCopyFailedException { + void initContext() throws SimpleWorkingCopyFactory.ReclaimFailedException { lenient().when(workingCopyContext.getInitializer()).thenReturn(initializer); lenient().when(workingCopyContext.getReclaimer()).thenReturn(reclaimer); @@ -73,7 +73,7 @@ class CachingAllWorkingCopyPoolTest { } @Test - void shouldCreateNewWorkdirForTheFirstRequest(@TempDir Path temp) throws WorkingCopyFailedException { + void shouldCreateNewWorkdirForTheFirstRequest(@TempDir Path temp) { when(workingCopyContext.getScmRepository()).thenReturn(REPOSITORY); when(workdirProvider.createNewWorkdir()).thenReturn(temp.toFile()); @@ -83,7 +83,7 @@ class CachingAllWorkingCopyPoolTest { } @Test - void shouldCreateWorkdirOnlyOnceForTheSameRepository(@TempDir Path temp) throws SimpleWorkingCopyFactory.ReclaimFailedException, WorkingCopyFailedException { + void shouldCreateWorkdirOnlyOnceForTheSameRepository(@TempDir Path temp) throws SimpleWorkingCopyFactory.ReclaimFailedException { when(workingCopyContext.getScmRepository()).thenReturn(REPOSITORY); when(workdirProvider.createNewWorkdir()).thenReturn(temp.toFile()); @@ -97,7 +97,7 @@ class CachingAllWorkingCopyPoolTest { } @Test - void shouldCacheOnlyOneWorkdirForRepository(@TempDir Path temp) throws SimpleWorkingCopyFactory.ReclaimFailedException, WorkingCopyFailedException { + void shouldCacheOnlyOneWorkdirForRepository(@TempDir Path temp) throws SimpleWorkingCopyFactory.ReclaimFailedException { when(workingCopyContext.getScmRepository()).thenReturn(REPOSITORY); File firstDirectory = temp.resolve("first").toFile(); firstDirectory.mkdirs(); diff --git a/scm-core/src/test/java/sonia/scm/repository/work/SimpleWorkingCopyFactoryTest.java b/scm-core/src/test/java/sonia/scm/repository/work/SimpleWorkingCopyFactoryTest.java index 00276fe83f..2e8e8ef5d2 100644 --- a/scm-core/src/test/java/sonia/scm/repository/work/SimpleWorkingCopyFactoryTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/work/SimpleWorkingCopyFactoryTest.java @@ -61,7 +61,7 @@ public class SimpleWorkingCopyFactoryTest { WorkdirProvider workdirProvider = new WorkdirProvider(temporaryFolder.newFolder()); WorkingCopyPool configurableTestWorkingCopyPool = new WorkingCopyPool() { @Override - public ParentAndClone getWorkingCopy(WorkingCopyContext context) throws WorkingCopyFailedException { + public ParentAndClone getWorkingCopy(WorkingCopyContext context) { workdir = workdirProvider.createNewWorkdir(); return context.getInitializer().initialize(workdir, context.getRequestedBranch()); } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitWorkingCopyInitializer.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitWorkingCopyInitializer.java index 02c735a42c..304a8893f9 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitWorkingCopyInitializer.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitWorkingCopyInitializer.java @@ -33,7 +33,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sonia.scm.repository.InternalRepositoryException; import sonia.scm.repository.work.SimpleWorkingCopyFactory; -import sonia.scm.repository.work.WorkingCopyFailedException; import sonia.scm.repository.work.WorkingCopyPool; import java.io.File; @@ -55,7 +54,7 @@ class GitWorkingCopyInitializer implements SimpleWorkingCopyFactory.WorkingCopyI } @Override - public WorkingCopyPool.ParentAndClone initialize(File target, String initialBranch) throws WorkingCopyFailedException { + public WorkingCopyPool.ParentAndClone initialize(File target, String initialBranch) { LOG.trace("clone repository {}", context.getRepository().getId()); long start = System.nanoTime(); try { diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactory.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactory.java index ae8a25426f..364c64ed69 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactory.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactory.java @@ -32,8 +32,8 @@ import com.aragost.javahg.commands.PullCommand; import com.aragost.javahg.commands.StatusCommand; import com.aragost.javahg.commands.UpdateCommand; import com.aragost.javahg.commands.flags.CloneCommandFlags; +import sonia.scm.repository.InternalRepositoryException; import sonia.scm.repository.work.SimpleWorkingCopyFactory; -import sonia.scm.repository.work.WorkingCopyFailedException; import sonia.scm.repository.work.WorkingCopyPool; import sonia.scm.repository.work.WorkingCopyPool.ParentAndClone; import sonia.scm.util.IOUtil; @@ -66,7 +66,7 @@ public class SimpleHgWorkingCopyFactory extends SimpleWorkingCopyFactory initialize(File workingCopy, String initialBranch) throws WorkingCopyFailedException { + public WorkingCopyPool.ParentAndClone initialize(File workingCopy, String initialBranch) { final SvnOperationFactory svnOperationFactory = new SvnOperationFactory(); SVNURL source; From 0f7e3563e10aa0694316c04983fd4d4358511b8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Thu, 14 May 2020 21:46:23 +0200 Subject: [PATCH 21/29] Fix doc --- .../sonia/scm/repository/work/SimpleWorkingCopyFactory.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/repository/work/SimpleWorkingCopyFactory.java b/scm-core/src/main/java/sonia/scm/repository/work/SimpleWorkingCopyFactory.java index 7e6a941871..fa22d80131 100644 --- a/scm-core/src/main/java/sonia/scm/repository/work/SimpleWorkingCopyFactory.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/SimpleWorkingCopyFactory.java @@ -26,7 +26,6 @@ package sonia.scm.repository.work; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import sonia.scm.repository.InternalRepositoryException; import sonia.scm.repository.RepositoryProvider; import javax.servlet.ServletContextEvent; @@ -41,10 +40,10 @@ import java.io.File; * implemented: * *
- *
{@link #getInitializer(C, File, String)}
+ *
{@link #getInitializer(C)}
*
Creates a new clone of the repository for the given context in the given * directory with the given branch checked out (if branches are supported).
- *
{@link #getReclaimer(C, File, String)}
+ *
{@link #getReclaimer(C)}
*
Reclaim the working directory with a already checked out clone of the * repository given in the context, so that the directory is not modified in * respect to the repository and the given branch is checked out (if branches From 73ef55921315805f20733e2ff6ce80600f2737dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Thu, 14 May 2020 22:04:55 +0200 Subject: [PATCH 22/29] Remove function creep --- .../work/CachingAllWorkingCopyPool.java | 12 +- .../work/NoneCachingWorkingCopyPool.java | 7 +- .../work/SimpleWorkingCopyFactory.java | 195 +++++++++--------- .../repository/work/WorkingCopyContext.java | 29 +-- .../scm/repository/work/WorkingCopyPool.java | 12 +- .../work/CachingAllWorkingCopyPoolTest.java | 25 +-- .../work/SimpleWorkingCopyFactoryTest.java | 6 +- 7 files changed, 130 insertions(+), 156 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/repository/work/CachingAllWorkingCopyPool.java b/scm-core/src/main/java/sonia/scm/repository/work/CachingAllWorkingCopyPool.java index bb64a82d88..40cdf97d27 100644 --- a/scm-core/src/main/java/sonia/scm/repository/work/CachingAllWorkingCopyPool.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/CachingAllWorkingCopyPool.java @@ -27,7 +27,6 @@ package sonia.scm.repository.work; import com.google.common.base.Stopwatch; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import sonia.scm.repository.RepositoryProvider; import sonia.scm.util.IOUtil; import javax.inject.Inject; @@ -49,13 +48,13 @@ public class CachingAllWorkingCopyPool implements WorkingCopyPool { } @Override - public ParentAndClone getWorkingCopy(WorkingCopyContext workingCopyContext) { + public ParentAndClone getWorkingCopy(WorkingCopyContext workingCopyContext) { String id = workingCopyContext.getScmRepository().getId(); File existingWorkdir = workdirs.remove(id); if (existingWorkdir != null) { Stopwatch stopwatch = Stopwatch.createStarted(); try { - ParentAndClone reclaimed = workingCopyContext.getReclaimer().reclaim(existingWorkdir, workingCopyContext.getRequestedBranch()); + ParentAndClone reclaimed = workingCopyContext.reclaim(existingWorkdir); LOG.debug("reclaimed workdir for {} in path {} in {}", workingCopyContext.getScmRepository().getNamespaceAndName(), existingWorkdir, stopwatch.stop()); return reclaimed; } catch (SimpleWorkingCopyFactory.ReclaimFailedException e) { @@ -66,17 +65,16 @@ public class CachingAllWorkingCopyPool implements WorkingCopyPool { return createNewWorkingCopy(workingCopyContext); } - private ParentAndClone createNewWorkingCopy(WorkingCopyContext workingCopyContext) { + private ParentAndClone createNewWorkingCopy(WorkingCopyContext workingCopyContext) { Stopwatch stopwatch = Stopwatch.createStarted(); File newWorkdir = workdirProvider.createNewWorkdir(); - SimpleWorkingCopyFactory.WorkingCopyInitializer initializer = workingCopyContext.getInitializer(); - ParentAndClone parentAndClone = initializer.initialize(newWorkdir, workingCopyContext.getRequestedBranch()); + ParentAndClone parentAndClone = workingCopyContext.initialize(newWorkdir); LOG.debug("initialized new workdir for {} in path {} in {}", workingCopyContext.getScmRepository().getNamespaceAndName(), newWorkdir, stopwatch.stop()); return parentAndClone; } @Override - public void contextClosed(WorkingCopyContext workingCopyContext, File workdir) { + public void contextClosed(WorkingCopyContext workingCopyContext, File workdir) { String id = workingCopyContext.getScmRepository().getId(); File putResult = workdirs.putIfAbsent(id, workdir); if (putResult != null && putResult != workdir) { diff --git a/scm-core/src/main/java/sonia/scm/repository/work/NoneCachingWorkingCopyPool.java b/scm-core/src/main/java/sonia/scm/repository/work/NoneCachingWorkingCopyPool.java index 630b36b470..f4b493d3ab 100644 --- a/scm-core/src/main/java/sonia/scm/repository/work/NoneCachingWorkingCopyPool.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/NoneCachingWorkingCopyPool.java @@ -24,7 +24,6 @@ package sonia.scm.repository.work; -import sonia.scm.repository.RepositoryProvider; import sonia.scm.util.IOUtil; import javax.inject.Inject; @@ -40,12 +39,12 @@ public class NoneCachingWorkingCopyPool implements WorkingCopyPool { } @Override - public ParentAndClone getWorkingCopy(WorkingCopyContext context) { - return context.getInitializer().initialize(workdirProvider.createNewWorkdir(), context.getRequestedBranch()); + public ParentAndClone getWorkingCopy(WorkingCopyContext context) { + return context.initialize(workdirProvider.createNewWorkdir()); } @Override - public void contextClosed(WorkingCopyContext workingCopyContext, File workdir) { + public void contextClosed(WorkingCopyContext workingCopyContext, File workdir) { IOUtil.deleteSilently(workdir); } diff --git a/scm-core/src/main/java/sonia/scm/repository/work/SimpleWorkingCopyFactory.java b/scm-core/src/main/java/sonia/scm/repository/work/SimpleWorkingCopyFactory.java index fa22d80131..727e54dffc 100644 --- a/scm-core/src/main/java/sonia/scm/repository/work/SimpleWorkingCopyFactory.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/SimpleWorkingCopyFactory.java @@ -55,115 +55,109 @@ import java.io.File; *
Closes resources allocated for the central repository.
*
*
- *                     ┌─────────────┐          ┌───────────────────────────┐                                                      ┌───────────────┐          ┌───────────────┐
- *                     │ModifyCommand│          │SimpleGitWorkingCopyFactory│                                                      │WorkingCopyPool│          │WorkdirProvider│
- *                     └──────┬──────┘          └─────────────┬─────────────┘                                                      └───────┬───────┘          └───────┬───────┘
- *                            │      createWorkingCopy        │                                                                            │                          │
- *                            │──────────────────────────────>│                                                                            │                          │
- *                            │                               │                                                                            │                          │
- *                            │                               ────┐                                                                        │                          │
- *                            │                                   │ createContext                                                          │                          │
- *                            │                               <───┘                                                                        │                          │
- *                            │                               │                                                                            │                          │
- *                            │                               │        create          ┌─────────┐                                         │                          │
- *                            │                               │──────────────────────> │Reclaimer│                                         │                          │
- *                            │                               │                        └────┬────┘                                         │                          │
- *                            │                               │                  create     │               ┌───────────┐                  │                          │
- *                            │                               │───────────────────────────────────────────> │Initializer│                  │                          │
- *                            │                               │                             │               └─────┬─────┘                  │                          │
- *                            │                               │                             │getWorkingCopy       │                        │                          │
- *                            │                               │───────────────────────────────────────────────────────────────────────────>│                          │
- *                            │                               │                             │                     │                        │                          │
- *                            │                               │                             │                     │                        │                          │
- *                            │                               │                             │                     │                        │                          │
- *                            │                               │                             │                     │                        │                          │
- *                            │                               │                             │                   reclaim                    │                          │
- *                            │                               │                             │<─────────────────────────────────────────────│                          │
- *                            │                               │                             │                     │                        │                          │
- *                            │                               │                             │                     │                        │                          │
- *                            │       ╔══════╤════════════════╪═════════════════════════════╪═════════════════════╪════════════════════════╪══════════════════════════╪═════════════════╗
- *                            │       ║ ALT  │  reclaim successful                          │                     │                        │                          │                 ║
- *                            │       ╟──────┘                │                             │                     │                        │                          │                 ║
- *                            │       ║                       │                             │                     │                        │                          │                 ║
- *                            │       ║                       │                             │─────────────────────────────────────────────>│                          │                 ║
- *                            │       ╠═══════════════════════╪═════════════════════════════╪═════════════════════╪════════════════════════╪══════════════════════════╪═════════════════╣
- *                            │       ║ [reclaim fails; create new]                         │                     │                        │                          │                 ║
- *                            │       ║                       │                          ReclaimFailedException   │                        │                          │                 ║
- *                            │       ║                       │───────────────────────────────────────────────────────────────────────────>│                          │                 ║
- *                            │       ║                       │                             │                     │                        │                          │                 ║
- *                            │       ║                       │                             │                     │                        │    createNewWorkdir      │                 ║
- *                            │       ║                       │                             │                     │                        │─────────────────────────>│                 ║
- *                            │       ║                       │                             │                     │                        │                          │                 ║
- *                            │       ║                       │                             │                     │                        │                          │                 ║
- *                            │       ║                       │                             │                     │                        │<─────────────────────────│                 ║
- *                            │       ║                       │                             │                     │                        │                          │                 ║
- *                            │       ║                       │                             │                     │      initialize        │                          │                 ║
- *                            │       ║                       │                             │                     │<───────────────────────│                          │                 ║
- *                            │       ║                       │                             │                     │                        │                          │                 ║
- *                            │       ║                       │                             │                     │                        │                          │                 ║
- *                            │       ║                       │                             │                     │───────────────────────>│                          │                 ║
- *                            │       ╚═══════════════════════╪═════════════════════════════╪═════════════════════╪════════════════════════╪══════════════════════════╪═════════════════╝
- *                            │                               │                             │                     │                        │                          │
- *                            │                               │                             │ParentAndClone       │                        │                          │
- *                            │                               │<───────────────────────────────────────────────────────────────────────────│                          │
- *                            │                               │                             │                     │                        │                          │
- *                            │                               │                             │                     │                        │                          │                  ┌───────────┐
- *                            │                               │────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────> │WorkingCopy│
- *                            │                               │                             │                     │                        │                          │                  └─────┬─────┘
- *                            │         WorkingCopy           │                             │                     │                        │                          │                        │
- *                            │<──────────────────────────────│                             │                     │                        │                          │                        │
- *                            │                               │                             │                     │                        │                          │                        │
- *                            .                               .                             .                     .                        .                          .                        .
- *                            .                               .                             .                     .                        .                          .                        .
- *                            .                               .                             .                     .                        .                          .                        .
- *                            .                               .                             .                     .                        .                          .                        .
- *                            │                               │                             │              doWork │                        │                          │                        │
- *                            │───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────>│
- *                            │                               │                             │                     │                        │                          │                        │
- *                            .                               .                             .                     .                        .                          .                        .
- *                            .                               .                             .                     .                        .                          .                        .
- *                            .                               .                             .                     .                        .                          .                        .
- *                            .                               .                             .                     .                        .                          .                        .
- *                            │                               │                             │               close │                        │                          │                        │
- *                            │───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────>│
- *                            │                               │                             │                     │                        │                          │                        │
- *                            │                               │                             │                     │         close          │                          │                        │
- *                            │                               │<───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────│
- *                            │                               │                             │                     │                        │                          │                        │
- *                            │                               ────┐                         │                     │                        │                          │                        │
- *                            │                                   │ closeWorkingCopy        │                     │                        │                          │                        │
- *                            │                               <───┘                         │                     │                        │                          │                        │
- *                            │                               │                             │                     │                        │                          │                        │
- *                            │                               ────┐                         │                     │                        │                          │                        │
- *                            │                                   │ closeRepository         │                     │                        │                          │                        │
- *                            │                               <───┘                         │                     │                        │                          │                        │
- *                            │                               │                             │                     │                        │                          │                        │
- *                            │                               │                             │ contextClosed       │                        │                          │                        │
- *                            │                               │───────────────────────────────────────────────────────────────────────────>│                          │                        │
+ *                     ┌─────────────┐          ┌───────────────────────────┐                                        ┌───────────────┐          ┌───────────────┐
+ *                     │ModifyCommand│          │SimpleGitWorkingCopyFactory│                                        │WorkingCopyPool│          │WorkdirProvider│
+ *                     └──────┬──────┘          └─────────────┬─────────────┘                                        └───────┬───────┘          └───────┬───────┘
+ *                            │      createWorkingCopy        │                                                              │                          │
+ *                            │──────────────────────────────>│                                                              │                          │
+ *                            │                               │                                                              │                          │
+ *                            │                               │        create          ┌──────────────────┐                  │                          │
+ *                            │                               │──────────────────────> │WorkingCopyContext│                  │                          │
+ *                            │                               │                        └────────┬─────────┘                  │                          │
+ *                            │                               │                       getWorkingCopy                         │                          │
+ *                            │                               │─────────────────────────────────────────────────────────────>│                          │
+ *                            │                               │                                 │                            │                          │
+ *                            │                               │                                 │                            │                          │
+ *                            │                               │                                 │                            │                          │
+ *                            │                               │                                 │                            │                          │
+ *                            │                               │                                 │          reclaim           │                          │
+ *                            │                               │                                 │ <──────────────────────────│                          │
+ *                            │                               │                                 │                            │                          │
+ *                            │                               │                                 │                            │                          │
+ *                            │                               │              ╔══════╤═══════════╪════════════════════════════╪══════════════════════════╪═════════════════╗
+ *                            │                               │              ║ ALT  │  reclaim successful                    │                          │                 ║
+ *                            │                               │              ╟──────┘           │                            │                          │                 ║
+ *                            │                               │              ║                  │                            │                          │                 ║
+ *                            │                               │              ║                  │ ──────────────────────────>│                          │                 ║
+ *                            │                               │              ╠══════════════════╪════════════════════════════╪══════════════════════════╪═════════════════╣
+ *                            │                               │              ║ [reclaim fails; create new]                   │                          │                 ║
+ *                            │                               │              ║                  │   ReclaimFailedException   │                          │                 ║
+ *                            │                               │              ║                  │ ──────────────────────────>│                          │                 ║
+ *                            │                               │              ║                  │                            │                          │                 ║
+ *                            │                               │              ║                  │                            │    createNewWorkdir      │                 ║
+ *                            │                               │              ║                  │                            │─────────────────────────>│                 ║
+ *                            │                               │              ║                  │                            │                          │                 ║
+ *                            │                               │              ║                  │                            │                          │                 ║
+ *                            │                               │              ║                  │                            │<─────────────────────────│                 ║
+ *                            │                               │              ║                  │                            │                          │                 ║
+ *                            │                               │              ║                  │         initialize         │                          │                 ║
+ *                            │                               │              ║                  │ <──────────────────────────│                          │                 ║
+ *                            │                               │              ║                  │                            │                          │                 ║
+ *                            │                               │              ║                  │                            │                          │                 ║
+ *                            │                               │              ║                  │ ──────────────────────────>│                          │                 ║
+ *                            │                               │              ╚══════════════════╪════════════════════════════╪══════════════════════════╪═════════════════╝
+ *                            │                               │                                 │                            │                          │
+ *                            │                               │                       ParentAndClone                         │                          │
+ *                            │                               │<─────────────────────────────────────────────────────────────│                          │
+ *                            │                               │                                 │                            │                          │
+ *                            │                               │                                 │                            │                          │                  ┌───────────┐
+ *                            │                               │──────────────────────────────────────────────────────────────────────────────────────────────────────────> │WorkingCopy│
+ *                            │                               │                                 │                            │                          │                  └─────┬─────┘
+ *                            │         WorkingCopy           │                                 │                            │                          │                        │
+ *                            │<──────────────────────────────│                                 │                            │                          │                        │
+ *                            │                               │                                 │                            │                          │                        │
+ *                            .                               .                                 .                            .                          .                        .
+ *                            .                               .                                 .                            .                          .                        .
+ *                            .                               .                                 .                            .                          .                        .
+ *                            .                               .                                 .                            .                          .                        .
+ *                            │                               │                                 │   doWork                   │                          │                        │
+ *                            │─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────>│
+ *                            │                               │                                 │                            │                          │                        │
+ *                            .                               .                                 .                            .                          .                        .
+ *                            .                               .                                 .                            .                          .                        .
+ *                            .                               .                                 .                            .                          .                        .
+ *                            .                               .                                 .                            .                          .                        .
+ *                            │                               │                                 │    close                   │                          │                        │
+ *                            │─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────>│
+ *                            │                               │                                 │                            │                          │                        │
+ *                            │                               │                                 │                    close   │                          │                        │
+ *                            │                               │<─────────────────────────────────────────────────────────────────────────────────────────────────────────────────│
+ *                            │                               │                                 │                            │                          │                        │
+ *                            │                               ────┐                             │                            │                          │                        │
+ *                            │                                   │ closeWorkingCopy            │                            │                          │                        │
+ *                            │                               <───┘                             │                            │                          │                        │
+ *                            │                               │                                 │                            │                          │                        │
+ *                            │                               ────┐                             │                            │                          │                        │
+ *                            │                                   │ closeRepository             │                            │                          │                        │
+ *                            │                               <───┘                             │                            │                          │                        │
+ *                            │                               │                                 │                            │                          │                        │
+ *                            │                               │                        contextClosed                         │                          │                        │
+ *                            │                               │─────────────────────────────────────────────────────────────>│                          │                        │
+ *                     ┌──────┴──────┐          ┌─────────────┴─────────────┐          ┌────────┴─────────┐          ┌───────┴───────┐          ┌───────┴───────┐          ┌─────┴─────┐
+ *                     │ModifyCommand│          │SimpleGitWorkingCopyFactory│          │WorkingCopyContext│          │WorkingCopyPool│          │WorkdirProvider│          │WorkingCopy│
+ *                     └─────────────┘          └───────────────────────────┘          └──────────────────┘          └───────────────┘          └───────────────┘          └───────────┘
  * 
- * + * * @param Type of central repository location * @param Type of working copy for repository * @param Type of repository context */ /* -http://www.plantuml.com/plantuml/uml/fPF1QiCm38RlVWgV0-a3U10wmZfss2ZTO6TZgqLCiOBjhCsUVeIcmKkPcx5RB7t_7qcsrY5g7xk6n3DRtFSrDursjgnUiMa97Z6-i_z0TwYvxJVQHFQzLD9uq16IbCZmMJDrjghPHJZ5l8tSWI6D3VYY67Kt14yE8sh2hyMI9BPb9dM051C7prqhttml8qj_BaVCD6KrrQakYAPumMNeZ84GzXs92IohIivi1520IRJNIE5k7BnqSCotSPgxgV5N6uq4zk5ae8t8xhhs8M3HRpr_eWK_3kq5ZcD2p82oci_isZEv1eNJjvZ2l_JlxBLLzYrjjGSNxvsjYTtoYowAF5hzs0sL5YfMgzLyTPAqiZoSRb66E43IQtvbHZn3B90dyNywxQ3bWCFvRvjbpYjV3nvMhC7Phg5l +http://www.plantuml.com/plantuml/uml/fPFHQlCm38Nl_HI-3gGFu1zCVyAwgutI3NPjRBM8ALQmdRNPqu_ITBX9yJ9sQUax9-H8MiTaGkfR4a_iS3yqtBR6krg_ODiHF69wu_2E_j1mDsoCJHm6gQGDO19aBL7WQospOiC-mIbLbRgOb9LPRSjCwW0v9Ww1-qw-Xa4cbW4i6Mp5H5Fh-TVLbJMKhZePUsiXndrFOgwejPOJOm4KuLkzDqZntvYCz72yQtAQcgZTHRynIE0UJXQwXEpl_uJ3i0tyWGx2cDup7CU6c02rdeQtA1ZqcD0GViBI4BoR6vVMHsrD09_-UzSG--NphweogcysMCcC4QlLQhhWMLivFhz-eYnnl4cbU2KZNY0MoBFw7vrsq774y_jt1sSlas_E7awimRk-fIy0 @startuml ModifyCommand->SimpleGitWorkingCopyFactory : createWorkingCopy -SimpleGitWorkingCopyFactory->SimpleGitWorkingCopyFactory:createContext -SimpleGitWorkingCopyFactory-> Reclaimer**:create -SimpleGitWorkingCopyFactory-> Initializer**:create +SimpleGitWorkingCopyFactory-> WorkingCopyContext**:create SimpleGitWorkingCopyFactory->WorkingCopyPool:getWorkingCopy group Try to reclaim -WorkingCopyPool->Reclaimer:reclaim +WorkingCopyPool->WorkingCopyContext:reclaim alt reclaim successful -Reclaimer->> WorkingCopyPool +WorkingCopyContext->> WorkingCopyPool else reclaim fails; create new -SimpleGitWorkingCopyFactory->x WorkingCopyPool:ReclaimFailedException +WorkingCopyContext->x WorkingCopyPool:ReclaimFailedException WorkingCopyPool->WorkdirProvider:createNewWorkdir WorkdirProvider->>WorkingCopyPool -WorkingCopyPool->Initializer:initialize -Initializer->> WorkingCopyPool +WorkingCopyPool->WorkingCopyContext:initialize +WorkingCopyContext->> WorkingCopyPool end WorkingCopyPool->>SimpleGitWorkingCopyFactory:ParentAndClone SimpleGitWorkingCopyFactory->WorkingCopy** @@ -176,8 +170,7 @@ WorkingCopy->SimpleGitWorkingCopyFactory:close SimpleGitWorkingCopyFactory->SimpleGitWorkingCopyFactory:closeWorkingCopy SimpleGitWorkingCopyFactory->SimpleGitWorkingCopyFactory:closeRepository SimpleGitWorkingCopyFactory->WorkingCopyPool:contextClosed -@enduml -*/ +@enduml*/ public abstract class SimpleWorkingCopyFactory implements WorkingCopyFactory, ServletContextListener { private static final Logger LOG = LoggerFactory.getLogger(SimpleWorkingCopyFactory.class); @@ -190,21 +183,21 @@ public abstract class SimpleWorkingCopyFactory createWorkingCopy(C repositoryContext, String initialBranch) { - WorkingCopyContext workingCopyContext = createWorkingCopyContext(repositoryContext, initialBranch); + WorkingCopyContext workingCopyContext = createWorkingCopyContext(repositoryContext, initialBranch); WorkingCopyPool.ParentAndClone parentAndClone = workingCopyPool.getWorkingCopy(workingCopyContext); return new WorkingCopy<>(parentAndClone.getClone(), parentAndClone.getParent(), () -> this.close(workingCopyContext, parentAndClone), parentAndClone.getDirectory()); } - private WorkingCopyContext createWorkingCopyContext(C repositoryContext, String initialBranch) { + private WorkingCopyContext createWorkingCopyContext(C repositoryContext, String initialBranch) { return new WorkingCopyContext<>( initialBranch, - repositoryContext, + repositoryContext.get(), getInitializer(repositoryContext), getReclaimer(repositoryContext) ); } - private void close(WorkingCopyContext workingCopyContext, WorkingCopyPool.ParentAndClone parentAndClone) { + private void close(WorkingCopyContext workingCopyContext, WorkingCopyPool.ParentAndClone parentAndClone) { try { closeWorkingCopy(parentAndClone.getClone()); } catch (Exception e) { diff --git a/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyContext.java b/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyContext.java index e4574bc454..0fa90729fa 100644 --- a/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyContext.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyContext.java @@ -25,38 +25,31 @@ package sonia.scm.repository.work; import sonia.scm.repository.Repository; -import sonia.scm.repository.RepositoryProvider; -public class WorkingCopyContext { +import java.io.File; + +public class WorkingCopyContext { private final String requestedBranch; - private final C context; + private final Repository repository; private final SimpleWorkingCopyFactory.WorkingCopyInitializer initializer; private final SimpleWorkingCopyFactory.WorkingCopyReclaimer reclaimer; - public WorkingCopyContext(String requestedBranch, C context, SimpleWorkingCopyFactory.WorkingCopyInitializer initializer, SimpleWorkingCopyFactory.WorkingCopyReclaimer reclaimer) { + public WorkingCopyContext(String requestedBranch, Repository repository, SimpleWorkingCopyFactory.WorkingCopyInitializer initializer, SimpleWorkingCopyFactory.WorkingCopyReclaimer reclaimer) { this.requestedBranch = requestedBranch; - this.context = context; + this.repository = repository; this.initializer = initializer; this.reclaimer = reclaimer; } public Repository getScmRepository() { - return context.get(); + return repository; } - public String getRequestedBranch() { - return requestedBranch; + public WorkingCopyPool.ParentAndClone reclaim(File workdir) throws SimpleWorkingCopyFactory.ReclaimFailedException { + return reclaimer.reclaim(workdir, requestedBranch); } - public C getContext() { - return context; - } - - public SimpleWorkingCopyFactory.WorkingCopyInitializer getInitializer() { - return initializer; - } - - public SimpleWorkingCopyFactory.WorkingCopyReclaimer getReclaimer() { - return reclaimer; + public WorkingCopyPool.ParentAndClone initialize(File workdir) { + return initializer.initialize(workdir, requestedBranch); } } diff --git a/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyPool.java b/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyPool.java index c389fe6bae..e64d52bddb 100644 --- a/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyPool.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyPool.java @@ -24,14 +24,12 @@ package sonia.scm.repository.work; -import sonia.scm.repository.RepositoryProvider; - import java.io.File; public interface WorkingCopyPool { - ParentAndClone getWorkingCopy(WorkingCopyContext context); + ParentAndClone getWorkingCopy(WorkingCopyContext context); - void contextClosed(WorkingCopyContext workingCopyContext, File workdir); + void contextClosed(WorkingCopyContext workingCopyContext, File workdir); void shutdown(); @@ -46,15 +44,15 @@ public interface WorkingCopyPool { this.directory = directory; } - public R getParent() { + R getParent() { return parent; } - public W getClone() { + W getClone() { return clone; } - public File getDirectory() { + File getDirectory() { return directory; } } diff --git a/scm-core/src/test/java/sonia/scm/repository/work/CachingAllWorkingCopyPoolTest.java b/scm-core/src/test/java/sonia/scm/repository/work/CachingAllWorkingCopyPoolTest.java index 51ed82a01a..3c378acea3 100644 --- a/scm-core/src/test/java/sonia/scm/repository/work/CachingAllWorkingCopyPoolTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/work/CachingAllWorkingCopyPoolTest.java @@ -32,7 +32,6 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import sonia.scm.repository.Repository; -import sonia.scm.repository.RepositoryProvider; import java.io.File; import java.nio.file.Path; @@ -55,20 +54,14 @@ class CachingAllWorkingCopyPoolTest { CachingAllWorkingCopyPool cachingAllWorkingCopyPool; @Mock - WorkingCopyContext workingCopyContext; - @Mock - SimpleWorkingCopyFactory.WorkingCopyInitializer initializer; - @Mock - SimpleWorkingCopyFactory.WorkingCopyReclaimer reclaimer; + WorkingCopyContext workingCopyContext; @BeforeEach void initContext() throws SimpleWorkingCopyFactory.ReclaimFailedException { - lenient().when(workingCopyContext.getInitializer()).thenReturn(initializer); - lenient().when(workingCopyContext.getReclaimer()).thenReturn(reclaimer); - lenient().when(initializer.initialize(any(), any())) + lenient().when(workingCopyContext.initialize(any())) .thenAnswer(invocationOnMock -> new WorkingCopyPool.ParentAndClone<>(null, null, invocationOnMock.getArgument(0, File.class))); - lenient().when(reclaimer.reclaim(any(), any())) + lenient().when(workingCopyContext.reclaim(any())) .thenAnswer(invocationOnMock -> new WorkingCopyPool.ParentAndClone<>(null, null, invocationOnMock.getArgument(0, File.class))); } @@ -79,7 +72,7 @@ class CachingAllWorkingCopyPoolTest { WorkingCopyPool.ParentAndClone workdir = cachingAllWorkingCopyPool.getWorkingCopy(workingCopyContext); - verify(initializer).initialize(temp.toFile(), null); + verify(workingCopyContext).initialize(temp.toFile()); } @Test @@ -91,8 +84,8 @@ class CachingAllWorkingCopyPoolTest { cachingAllWorkingCopyPool.contextClosed(workingCopyContext, firstWorkdir.getDirectory()); WorkingCopyPool.ParentAndClone secondWorkdir = cachingAllWorkingCopyPool.getWorkingCopy(workingCopyContext); - verify(initializer).initialize(temp.toFile(), null); - verify(reclaimer).reclaim(temp.toFile(), null); + verify(workingCopyContext).initialize(temp.toFile()); + verify(workingCopyContext).reclaim(temp.toFile()); assertThat(secondWorkdir.getDirectory()).isEqualTo(temp.toFile()); } @@ -112,9 +105,9 @@ class CachingAllWorkingCopyPoolTest { cachingAllWorkingCopyPool.contextClosed(workingCopyContext, firstWorkdir.getDirectory()); cachingAllWorkingCopyPool.contextClosed(workingCopyContext, secondWorkdir.getDirectory()); - verify(reclaimer, never()).reclaim(any(), any()); - verify(initializer).initialize(firstDirectory, null); - verify(initializer).initialize(secondDirectory, null); + verify(workingCopyContext, never()).reclaim(any()); + verify(workingCopyContext).initialize(firstDirectory); + verify(workingCopyContext).initialize(secondDirectory); assertThat(firstWorkdir.getDirectory()).isNotEqualTo(secondWorkdir.getDirectory()); assertThat(firstWorkdir.getDirectory()).exists(); assertThat(secondWorkdir.getDirectory()).doesNotExist(); diff --git a/scm-core/src/test/java/sonia/scm/repository/work/SimpleWorkingCopyFactoryTest.java b/scm-core/src/test/java/sonia/scm/repository/work/SimpleWorkingCopyFactoryTest.java index 2e8e8ef5d2..b3e2cb5e07 100644 --- a/scm-core/src/test/java/sonia/scm/repository/work/SimpleWorkingCopyFactoryTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/work/SimpleWorkingCopyFactoryTest.java @@ -61,13 +61,13 @@ public class SimpleWorkingCopyFactoryTest { WorkdirProvider workdirProvider = new WorkdirProvider(temporaryFolder.newFolder()); WorkingCopyPool configurableTestWorkingCopyPool = new WorkingCopyPool() { @Override - public ParentAndClone getWorkingCopy(WorkingCopyContext context) { + public ParentAndClone getWorkingCopy(WorkingCopyContext context) { workdir = workdirProvider.createNewWorkdir(); - return context.getInitializer().initialize(workdir, context.getRequestedBranch()); + return context.initialize(workdir); } @Override - public void contextClosed(WorkingCopyContext createWorkdirContext, File workdir) { + public void contextClosed(WorkingCopyContext createWorkdirContext, File workdir) { if (!workdirIsCached) { IOUtil.deleteSilently(workdir); } From 7e945afc43c91016a24817096137f25a8400de07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Thu, 14 May 2020 23:01:48 +0200 Subject: [PATCH 23/29] Keep ParentAndClone inside working copy factories --- .../work/CachingAllWorkingCopyPool.java | 10 +- .../work/NoneCachingWorkingCopyPool.java | 4 +- .../work/SimpleWorkingCopyFactory.java | 290 +++++++++++------- .../repository/work/WorkingCopyContext.java | 55 ---- .../scm/repository/work/WorkingCopyPool.java | 28 +- .../work/CachingAllWorkingCopyPoolTest.java | 16 +- .../work/SimpleWorkingCopyFactoryTest.java | 6 +- .../spi/GitWorkingCopyInitializer.java | 6 +- .../spi/GitWorkingCopyReclaimer.java | 6 +- .../spi/SimpleHgWorkingCopyFactory.java | 1 - .../spi/SvnWorkingCopyInitializer.java | 6 +- .../spi/SvnWorkingCopyReclaimer.java | 6 +- 12 files changed, 206 insertions(+), 228 deletions(-) delete mode 100644 scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyContext.java diff --git a/scm-core/src/main/java/sonia/scm/repository/work/CachingAllWorkingCopyPool.java b/scm-core/src/main/java/sonia/scm/repository/work/CachingAllWorkingCopyPool.java index 40cdf97d27..190a7bb58a 100644 --- a/scm-core/src/main/java/sonia/scm/repository/work/CachingAllWorkingCopyPool.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/CachingAllWorkingCopyPool.java @@ -48,13 +48,13 @@ public class CachingAllWorkingCopyPool implements WorkingCopyPool { } @Override - public ParentAndClone getWorkingCopy(WorkingCopyContext workingCopyContext) { + public WorkingCopy getWorkingCopy(SimpleWorkingCopyFactory.WorkingCopyContext workingCopyContext) { String id = workingCopyContext.getScmRepository().getId(); File existingWorkdir = workdirs.remove(id); if (existingWorkdir != null) { Stopwatch stopwatch = Stopwatch.createStarted(); try { - ParentAndClone reclaimed = workingCopyContext.reclaim(existingWorkdir); + WorkingCopy reclaimed = workingCopyContext.reclaim(existingWorkdir); LOG.debug("reclaimed workdir for {} in path {} in {}", workingCopyContext.getScmRepository().getNamespaceAndName(), existingWorkdir, stopwatch.stop()); return reclaimed; } catch (SimpleWorkingCopyFactory.ReclaimFailedException e) { @@ -65,16 +65,16 @@ public class CachingAllWorkingCopyPool implements WorkingCopyPool { return createNewWorkingCopy(workingCopyContext); } - private ParentAndClone createNewWorkingCopy(WorkingCopyContext workingCopyContext) { + private WorkingCopy createNewWorkingCopy(SimpleWorkingCopyFactory.WorkingCopyContext workingCopyContext) { Stopwatch stopwatch = Stopwatch.createStarted(); File newWorkdir = workdirProvider.createNewWorkdir(); - ParentAndClone parentAndClone = workingCopyContext.initialize(newWorkdir); + WorkingCopy parentAndClone = workingCopyContext.initialize(newWorkdir); LOG.debug("initialized new workdir for {} in path {} in {}", workingCopyContext.getScmRepository().getNamespaceAndName(), newWorkdir, stopwatch.stop()); return parentAndClone; } @Override - public void contextClosed(WorkingCopyContext workingCopyContext, File workdir) { + public void contextClosed(SimpleWorkingCopyFactory.WorkingCopyContext workingCopyContext, File workdir) { String id = workingCopyContext.getScmRepository().getId(); File putResult = workdirs.putIfAbsent(id, workdir); if (putResult != null && putResult != workdir) { diff --git a/scm-core/src/main/java/sonia/scm/repository/work/NoneCachingWorkingCopyPool.java b/scm-core/src/main/java/sonia/scm/repository/work/NoneCachingWorkingCopyPool.java index f4b493d3ab..9e9859d27f 100644 --- a/scm-core/src/main/java/sonia/scm/repository/work/NoneCachingWorkingCopyPool.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/NoneCachingWorkingCopyPool.java @@ -39,12 +39,12 @@ public class NoneCachingWorkingCopyPool implements WorkingCopyPool { } @Override - public ParentAndClone getWorkingCopy(WorkingCopyContext context) { + public WorkingCopy getWorkingCopy(SimpleWorkingCopyFactory.WorkingCopyContext context) { return context.initialize(workdirProvider.createNewWorkdir()); } @Override - public void contextClosed(WorkingCopyContext workingCopyContext, File workdir) { + public void contextClosed(SimpleWorkingCopyFactory.WorkingCopyContext workingCopyContext, File workdir) { IOUtil.deleteSilently(workdir); } diff --git a/scm-core/src/main/java/sonia/scm/repository/work/SimpleWorkingCopyFactory.java b/scm-core/src/main/java/sonia/scm/repository/work/SimpleWorkingCopyFactory.java index 727e54dffc..7ed74c4e11 100644 --- a/scm-core/src/main/java/sonia/scm/repository/work/SimpleWorkingCopyFactory.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/SimpleWorkingCopyFactory.java @@ -26,6 +26,7 @@ package sonia.scm.repository.work; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryProvider; import javax.servlet.ServletContextEvent; @@ -55,95 +56,102 @@ import java.io.File; *
Closes resources allocated for the central repository.
*
*
- *                     ┌─────────────┐          ┌───────────────────────────┐                                        ┌───────────────┐          ┌───────────────┐
- *                     │ModifyCommand│          │SimpleGitWorkingCopyFactory│                                        │WorkingCopyPool│          │WorkdirProvider│
- *                     └──────┬──────┘          └─────────────┬─────────────┘                                        └───────┬───────┘          └───────┬───────┘
- *                            │      createWorkingCopy        │                                                              │                          │
- *                            │──────────────────────────────>│                                                              │                          │
- *                            │                               │                                                              │                          │
- *                            │                               │        create          ┌──────────────────┐                  │                          │
- *                            │                               │──────────────────────> │WorkingCopyContext│                  │                          │
- *                            │                               │                        └────────┬─────────┘                  │                          │
- *                            │                               │                       getWorkingCopy                         │                          │
- *                            │                               │─────────────────────────────────────────────────────────────>│                          │
- *                            │                               │                                 │                            │                          │
- *                            │                               │                                 │                            │                          │
- *                            │                               │                                 │                            │                          │
- *                            │                               │                                 │                            │                          │
- *                            │                               │                                 │          reclaim           │                          │
- *                            │                               │                                 │ <──────────────────────────│                          │
- *                            │                               │                                 │                            │                          │
- *                            │                               │                                 │                            │                          │
- *                            │                               │              ╔══════╤═══════════╪════════════════════════════╪══════════════════════════╪═════════════════╗
- *                            │                               │              ║ ALT  │  reclaim successful                    │                          │                 ║
- *                            │                               │              ╟──────┘           │                            │                          │                 ║
- *                            │                               │              ║                  │                            │                          │                 ║
- *                            │                               │              ║                  │ ──────────────────────────>│                          │                 ║
- *                            │                               │              ╠══════════════════╪════════════════════════════╪══════════════════════════╪═════════════════╣
- *                            │                               │              ║ [reclaim fails; create new]                   │                          │                 ║
- *                            │                               │              ║                  │   ReclaimFailedException   │                          │                 ║
- *                            │                               │              ║                  │ ──────────────────────────>│                          │                 ║
- *                            │                               │              ║                  │                            │                          │                 ║
- *                            │                               │              ║                  │                            │    createNewWorkdir      │                 ║
- *                            │                               │              ║                  │                            │─────────────────────────>│                 ║
- *                            │                               │              ║                  │                            │                          │                 ║
- *                            │                               │              ║                  │                            │                          │                 ║
- *                            │                               │              ║                  │                            │<─────────────────────────│                 ║
- *                            │                               │              ║                  │                            │                          │                 ║
- *                            │                               │              ║                  │         initialize         │                          │                 ║
- *                            │                               │              ║                  │ <──────────────────────────│                          │                 ║
- *                            │                               │              ║                  │                            │                          │                 ║
- *                            │                               │              ║                  │                            │                          │                 ║
- *                            │                               │              ║                  │ ──────────────────────────>│                          │                 ║
- *                            │                               │              ╚══════════════════╪════════════════════════════╪══════════════════════════╪═════════════════╝
- *                            │                               │                                 │                            │                          │
- *                            │                               │                       ParentAndClone                         │                          │
- *                            │                               │<─────────────────────────────────────────────────────────────│                          │
- *                            │                               │                                 │                            │                          │
- *                            │                               │                                 │                            │                          │                  ┌───────────┐
- *                            │                               │──────────────────────────────────────────────────────────────────────────────────────────────────────────> │WorkingCopy│
- *                            │                               │                                 │                            │                          │                  └─────┬─────┘
- *                            │         WorkingCopy           │                                 │                            │                          │                        │
- *                            │<──────────────────────────────│                                 │                            │                          │                        │
- *                            │                               │                                 │                            │                          │                        │
- *                            .                               .                                 .                            .                          .                        .
- *                            .                               .                                 .                            .                          .                        .
- *                            .                               .                                 .                            .                          .                        .
- *                            .                               .                                 .                            .                          .                        .
- *                            │                               │                                 │   doWork                   │                          │                        │
- *                            │─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────>│
- *                            │                               │                                 │                            │                          │                        │
- *                            .                               .                                 .                            .                          .                        .
- *                            .                               .                                 .                            .                          .                        .
- *                            .                               .                                 .                            .                          .                        .
- *                            .                               .                                 .                            .                          .                        .
- *                            │                               │                                 │    close                   │                          │                        │
- *                            │─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────>│
- *                            │                               │                                 │                            │                          │                        │
- *                            │                               │                                 │                    close   │                          │                        │
- *                            │                               │<─────────────────────────────────────────────────────────────────────────────────────────────────────────────────│
- *                            │                               │                                 │                            │                          │                        │
- *                            │                               ────┐                             │                            │                          │                        │
- *                            │                                   │ closeWorkingCopy            │                            │                          │                        │
- *                            │                               <───┘                             │                            │                          │                        │
- *                            │                               │                                 │                            │                          │                        │
- *                            │                               ────┐                             │                            │                          │                        │
- *                            │                                   │ closeRepository             │                            │                          │                        │
- *                            │                               <───┘                             │                            │                          │                        │
- *                            │                               │                                 │                            │                          │                        │
- *                            │                               │                        contextClosed                         │                          │                        │
- *                            │                               │─────────────────────────────────────────────────────────────>│                          │                        │
- *                     ┌──────┴──────┐          ┌─────────────┴─────────────┐          ┌────────┴─────────┐          ┌───────┴───────┐          ┌───────┴───────┐          ┌─────┴─────┐
- *                     │ModifyCommand│          │SimpleGitWorkingCopyFactory│          │WorkingCopyContext│          │WorkingCopyPool│          │WorkdirProvider│          │WorkingCopy│
- *                     └─────────────┘          └───────────────────────────┘          └──────────────────┘          └───────────────┘          └───────────────┘          └───────────┘
+ *                     ┌─────────────┐          ┌───────────────────────────┐                                        ┌───────────────┐                                 ┌───────────────┐
+ *                     │ModifyCommand│          │SimpleGitWorkingCopyFactory│                                        │WorkingCopyPool│                                 │WorkdirProvider│
+ *                     └──────┬──────┘          └─────────────┬─────────────┘                                        └───────┬───────┘                                 └───────┬───────┘
+ *                            │      createWorkingCopy        │                                                              │                                                 │
+ *                            │──────────────────────────────>│                                                              │                                                 │
+ *                            │                               │                                                              │                                                 │
+ *                            │                               │        create          ┌──────────────────┐                  │                                                 │
+ *                            │                               │──────────────────────> │WorkingCopyContext│                  │                                                 │
+ *                            │                               │                        └────────┬─────────┘                  │                                                 │
+ *                            │                               │                       getWorkingCopy                         │                                                 │
+ *                            │                               │─────────────────────────────────────────────────────────────>│                                                 │
+ *                            │                               │                                 │                            │                                                 │
+ *                            │                               │                                 │                            │                                                 │
+ *                            │                               │                                 │                            │                                                 │
+ *                            │                               │                                 │                            │                                                 │
+ *                            │                               │                                 │          reclaim           │                                                 │
+ *                            │                               │                                 │ <──────────────────────────│                                                 │
+ *                            │                               │                                 │                            │                                                 │
+ *                            │                               │                                 │                            │                                                 │
+ *                            │                               │              ╔══════╤═══════════╪════════════════════════════╪═════════════════════════════════════════════════╪═════════════════╗
+ *                            │                               │              ║ ALT  │  reclaim successful                    │                                                 │                 ║
+ *                            │                               │              ╟──────┘           │                            │                                                 │                 ║
+ *                            │                               │              ║                  │                            │                  ┌───────────┐                  │                 ║
+ *                            │                               │              ║                  │ ─────────────────────────────────────────────>│WorkingCopy│                  │                 ║
+ *                            │                               │              ║                  │                            │                  └─────┬─────┘                  │                 ║
+ *                            │                               │              ║                  │        WorkingCopy         │                                                 │                 ║
+ *                            │                               │              ║                  │ ──────────────────────────>│                                                 │                 ║
+ *                            │                               │              ╠══════════════════╪════════════════════════════╪═════════════════════════════════════════════════╪═════════════════╣
+ *                            │                               │              ║ [reclaim fails; create new]                   │                                                 │                 ║
+ *                            │                               │              ║                  │   ReclaimFailedException   │                                                 │                 ║
+ *                            │                               │              ║                  │ ──────────────────────────>│                                                 │                 ║
+ *                            │                               │              ║                  │                            │                                                 │                 ║
+ *                            │                               │              ║                  │                            │                createNewWorkdir                 │                 ║
+ *                            │                               │              ║                  │                            │────────────────────────────────────────────────>│                 ║
+ *                            │                               │              ║                  │                            │                                                 │                 ║
+ *                            │                               │              ║                  │                            │                                                 │                 ║
+ *                            │                               │              ║                  │                            │<────────────────────────────────────────────────│                 ║
+ *                            │                               │              ║                  │                            │                                                 │                 ║
+ *                            │                               │              ║                  │         initialize         │                                                 │                 ║
+ *                            │                               │              ║                  │ <──────────────────────────│                                                 │                 ║
+ *                            │                               │              ║                  │                            │                                                 │                 ║
+ *                            │                               │              ║                  │                            │                  ┌───────────┐                  │                 ║
+ *                            │                               │              ║                  │ ─────────────────────────────────────────────>│WorkingCopy│                  │                 ║
+ *                            │                               │              ║                  │                            │                  └─────┬─────┘                  │                 ║
+ *                            │                               │              ║                  │        WorkingCopy         │                        │                        │                 ║
+ *                            │                               │              ║                  │ ──────────────────────────>│                        │                        │                 ║
+ *                            │                               │              ╚══════════════════╪════════════════════════════╪════════════════════════╪════════════════════════╪═════════════════╝
+ *                            │                               │                                 │                            │                        │                        │
+ *                            │                               │                         WorkingCopy                          │                        │                        │
+ *                            │                               │<─────────────────────────────────────────────────────────────│                        │                        │
+ *                            │                               │                                 │                            │                        │                        │
+ *                            │         WorkingCopy           │                                 │                            │                        │                        │
+ *                            │<──────────────────────────────│                                 │                            │                        │                        │
+ *                            │                               │                                 │                            │                        │                        │
+ *                            .                               .                                 .                            .                        .                        .
+ *                            .                               .                                 .                            .                        .                        .
+ *                            .                               .                                 .                            .                        .                        .
+ *                            .                               .                                 .                            .                        .                        .
+ *                            │                               │                        doWork   │                            │                        │                        │
+ *                            │──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────>│                        │
+ *                            │                               │                                 │                            │                        │                        │
+ *                            .                               .                                 .                            .                        .                        .
+ *                            .                               .                                 .                            .                        .                        .
+ *                            .                               .                                 .                            .                        .                        .
+ *                            .                               .                                 .                            .                        .                        .
+ *                            │                               │                        close    │                            │                        │                        │
+ *                            │──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────>│                        │
+ *                            │                               │                                 │                            │                        │                        │
+ *                            │                               │                                 │      close                 │                        │                        │
+ *                            │                               │<──────────────────────────────────────────────────────────────────────────────────────│                        │
+ *                            │                               │                                 │                            │                        │                        │
+ *                            │                               ────┐                             │                            │                        │                        │
+ *                            │                                   │ closeWorkingCopy            │                            │                        │                        │
+ *                            │                               <───┘                             │                            │                        │                        │
+ *                            │                               │                                 │                            │                        │                        │
+ *                            │                               ────┐                             │                            │                        │                        │
+ *                            │                                   │ closeRepository             │                            │                        │                        │
+ *                            │                               <───┘                             │                            │                        │                        │
+ *                            │                               │                                 │                            │                        │                        │
+ *                            │                               │                        contextClosed                         │                        │                        │
+ *                            │                               │─────────────────────────────────────────────────────────────>│                        │                        │
+ *                            │                               │                                 │                            │                        │                        │
+ *                            │                               │                                 │                            ────┐                    │                        │
+ *                            │                               │                                 │                                │ cacheDirectory     │                        │
+ *                            │                               │                                 │                            <───┘                    │                        │
+ *                     ┌──────┴──────┐          ┌─────────────┴─────────────┐          ┌────────┴─────────┐          ┌───────┴───────┐          ┌─────┴─────┐          ┌───────┴───────┐
+ *                     │ModifyCommand│          │SimpleGitWorkingCopyFactory│          │WorkingCopyContext│          │WorkingCopyPool│          │WorkingCopy│          │WorkdirProvider│
+ *                     └─────────────┘          └───────────────────────────┘          └──────────────────┘          └───────────────┘          └───────────┘          └───────────────┘
  * 
- * + * * @param Type of central repository location * @param Type of working copy for repository * @param Type of repository context */ /* -http://www.plantuml.com/plantuml/uml/fPFHQlCm38Nl_HI-3gGFu1zCVyAwgutI3NPjRBM8ALQmdRNPqu_ITBX9yJ9sQUax9-H8MiTaGkfR4a_iS3yqtBR6krg_ODiHF69wu_2E_j1mDsoCJHm6gQGDO19aBL7WQospOiC-mIbLbRgOb9LPRSjCwW0v9Ww1-qw-Xa4cbW4i6Mp5H5Fh-TVLbJMKhZePUsiXndrFOgwejPOJOm4KuLkzDqZntvYCz72yQtAQcgZTHRynIE0UJXQwXEpl_uJ3i0tyWGx2cDup7CU6c02rdeQtA1ZqcD0GViBI4BoR6vVMHsrD09_-UzSG--NphweogcysMCcC4QlLQhhWMLivFhz-eYnnl4cbU2KZNY0MoBFw7vrsq774y_jt1sSlas_E7awimRk-fIy0 +http://www.plantuml.com/plantuml/uml/jLF1JiCm3BtdAtAkr7r0aQf9XN42JGE9SvHumyA9goHbAr-FnZgKDbCPGXnZl_ViFDlB49MFdINnm0QtVSFMAcVA-WbjIt2FyONz6xfTmss_KZgoxsKbjGSL8Kc96NnPooJOi8jmY4LHdKJccKbipKpL3bAOs7dkMldiUnbPUj2aq8e9fwppwjKPgoYUUJ9qMaC8suv4pXYf5CL5H2sdxQQz0WNuhhLLIE5cy54ws5yKF6I2cnD_fP30t1qqj17PNVwoGR_s_8u6_E3r8-o7X9W0odfgzLKseiE8Yl03_iSoP_8svbQpabVlP3rQ-35niLXCxo59LuQFhvzGcZYCR9azgW4-WxY2diJ_gBI1bWCUtx-xJtqQR7FKo6UNmvL-XLlqy2Kdbk1CP-aJ @startuml ModifyCommand->SimpleGitWorkingCopyFactory : createWorkingCopy SimpleGitWorkingCopyFactory-> WorkingCopyContext**:create @@ -151,16 +159,17 @@ SimpleGitWorkingCopyFactory->WorkingCopyPool:getWorkingCopy group Try to reclaim WorkingCopyPool->WorkingCopyContext:reclaim alt reclaim successful -WorkingCopyContext->> WorkingCopyPool +WorkingCopyContext->WorkingCopy** +WorkingCopyContext->> WorkingCopyPool:WorkingCopy else reclaim fails; create new WorkingCopyContext->x WorkingCopyPool:ReclaimFailedException WorkingCopyPool->WorkdirProvider:createNewWorkdir WorkdirProvider->>WorkingCopyPool WorkingCopyPool->WorkingCopyContext:initialize -WorkingCopyContext->> WorkingCopyPool +WorkingCopyContext->WorkingCopy** +WorkingCopyContext->> WorkingCopyPool:WorkingCopy end -WorkingCopyPool->>SimpleGitWorkingCopyFactory:ParentAndClone -SimpleGitWorkingCopyFactory->WorkingCopy** +WorkingCopyPool->>SimpleGitWorkingCopyFactory: WorkingCopy SimpleGitWorkingCopyFactory->>ModifyCommand: WorkingCopy ... ModifyCommand->WorkingCopy:doWork @@ -170,7 +179,9 @@ WorkingCopy->SimpleGitWorkingCopyFactory:close SimpleGitWorkingCopyFactory->SimpleGitWorkingCopyFactory:closeWorkingCopy SimpleGitWorkingCopyFactory->SimpleGitWorkingCopyFactory:closeRepository SimpleGitWorkingCopyFactory->WorkingCopyPool:contextClosed -@enduml*/ +WorkingCopyPool->WorkingCopyPool:cacheDirectory +@enduml +*/ public abstract class SimpleWorkingCopyFactory implements WorkingCopyFactory, ServletContextListener { private static final Logger LOG = LoggerFactory.getLogger(SimpleWorkingCopyFactory.class); @@ -183,38 +194,17 @@ public abstract class SimpleWorkingCopyFactory createWorkingCopy(C repositoryContext, String initialBranch) { - WorkingCopyContext workingCopyContext = createWorkingCopyContext(repositoryContext, initialBranch); - WorkingCopyPool.ParentAndClone parentAndClone = workingCopyPool.getWorkingCopy(workingCopyContext); - return new WorkingCopy<>(parentAndClone.getClone(), parentAndClone.getParent(), () -> this.close(workingCopyContext, parentAndClone), parentAndClone.getDirectory()); + WorkingCopyContext workingCopyContext = createWorkingCopyContext(repositoryContext, initialBranch); + return workingCopyPool.getWorkingCopy(workingCopyContext); } - private WorkingCopyContext createWorkingCopyContext(C repositoryContext, String initialBranch) { - return new WorkingCopyContext<>( + private WorkingCopyContext createWorkingCopyContext(C repositoryContext, String initialBranch) { + return new WorkingCopyContext( initialBranch, - repositoryContext.get(), - getInitializer(repositoryContext), - getReclaimer(repositoryContext) + repositoryContext ); } - private void close(WorkingCopyContext workingCopyContext, WorkingCopyPool.ParentAndClone parentAndClone) { - try { - closeWorkingCopy(parentAndClone.getClone()); - } catch (Exception e) { - LOG.warn("could not close clone for {} in directory {}", workingCopyContext.getScmRepository(), parentAndClone.getDirectory(), e); - } - try { - closeRepository(parentAndClone.getParent()); - } catch (Exception e) { - LOG.warn("could not close central repository for {}", workingCopyContext.getScmRepository(), e); - } - try { - workingCopyPool.contextClosed(workingCopyContext, parentAndClone.getDirectory()); - } catch (Exception e) { - LOG.warn("could not close context for {} with directory {}", workingCopyContext.getScmRepository(), parentAndClone.getDirectory(), e); - } - } - @Override public void contextDestroyed(ServletContextEvent sce) { workingCopyPool.shutdown(); @@ -227,12 +217,12 @@ public abstract class SimpleWorkingCopyFactory { - WorkingCopyPool.ParentAndClone initialize(File target, String initialBranch); + ParentAndClone initialize(File target, String initialBranch); } @FunctionalInterface public interface WorkingCopyReclaimer { - WorkingCopyPool.ParentAndClone reclaim(File target, String initialBranch) throws ReclaimFailedException; + ParentAndClone reclaim(File target, String initialBranch) throws ReclaimFailedException; } protected abstract WorkingCopyInitializer getInitializer(C context); @@ -260,4 +250,72 @@ public abstract class SimpleWorkingCopyFactory { + private final R parent; + private final W clone; + private final File directory; + + public ParentAndClone(R parent, W clone, File directory) { + this.parent = parent; + this.clone = clone; + this.directory = directory; + } + + R getParent() { + return parent; + } + + W getClone() { + return clone; + } + + File getDirectory() { + return directory; + } + } + + public class WorkingCopyContext { + private final String requestedBranch; + private final C repositoryContext; + + public WorkingCopyContext(String requestedBranch, C repositoryContext) { + this.requestedBranch = requestedBranch; + this.repositoryContext = repositoryContext; + } + + public Repository getScmRepository() { + return repositoryContext.get(); + } + + public WorkingCopy reclaim(File workdir) throws SimpleWorkingCopyFactory.ReclaimFailedException { + return createWorkingCopyFromParentAndClone(getReclaimer(repositoryContext).reclaim(workdir, requestedBranch)); + } + + public WorkingCopy initialize(File workdir) { + return createWorkingCopyFromParentAndClone(getInitializer(repositoryContext).initialize(workdir, requestedBranch)); + } + + public WorkingCopy createWorkingCopyFromParentAndClone(ParentAndClone parentAndClone) { + return new WorkingCopy<>(parentAndClone.getClone(), parentAndClone.getParent(), () -> close(parentAndClone), parentAndClone.getDirectory()); + } + + private void close(ParentAndClone parentAndClone) { + try { + closeWorkingCopy(parentAndClone.getClone()); + } catch (Exception e) { + LOG.warn("could not close clone for {} in directory {}", getScmRepository(), parentAndClone.getDirectory(), e); + } + try { + closeRepository(parentAndClone.getParent()); + } catch (Exception e) { + LOG.warn("could not close central repository for {}", getScmRepository(), e); + } + try { + workingCopyPool.contextClosed(this, parentAndClone.getDirectory()); + } catch (Exception e) { + LOG.warn("could not close context for {} with directory {}", getScmRepository(), parentAndClone.getDirectory(), e); + } + } + } } diff --git a/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyContext.java b/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyContext.java deleted file mode 100644 index 0fa90729fa..0000000000 --- a/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyContext.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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.repository.work; - -import sonia.scm.repository.Repository; - -import java.io.File; - -public class WorkingCopyContext { - private final String requestedBranch; - private final Repository repository; - private final SimpleWorkingCopyFactory.WorkingCopyInitializer initializer; - private final SimpleWorkingCopyFactory.WorkingCopyReclaimer reclaimer; - - public WorkingCopyContext(String requestedBranch, Repository repository, SimpleWorkingCopyFactory.WorkingCopyInitializer initializer, SimpleWorkingCopyFactory.WorkingCopyReclaimer reclaimer) { - this.requestedBranch = requestedBranch; - this.repository = repository; - this.initializer = initializer; - this.reclaimer = reclaimer; - } - - public Repository getScmRepository() { - return repository; - } - - public WorkingCopyPool.ParentAndClone reclaim(File workdir) throws SimpleWorkingCopyFactory.ReclaimFailedException { - return reclaimer.reclaim(workdir, requestedBranch); - } - - public WorkingCopyPool.ParentAndClone initialize(File workdir) { - return initializer.initialize(workdir, requestedBranch); - } -} diff --git a/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyPool.java b/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyPool.java index e64d52bddb..472363ceb7 100644 --- a/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyPool.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/WorkingCopyPool.java @@ -27,33 +27,9 @@ package sonia.scm.repository.work; import java.io.File; public interface WorkingCopyPool { - ParentAndClone getWorkingCopy(WorkingCopyContext context); + WorkingCopy getWorkingCopy(SimpleWorkingCopyFactory.WorkingCopyContext context); - void contextClosed(WorkingCopyContext workingCopyContext, File workdir); + void contextClosed(SimpleWorkingCopyFactory.WorkingCopyContext workingCopyContext, File workdir); void shutdown(); - - class ParentAndClone { - private final R parent; - private final W clone; - private final File directory; - - public ParentAndClone(R parent, W clone, File directory) { - this.parent = parent; - this.clone = clone; - this.directory = directory; - } - - R getParent() { - return parent; - } - - W getClone() { - return clone; - } - - File getDirectory() { - return directory; - } - } } diff --git a/scm-core/src/test/java/sonia/scm/repository/work/CachingAllWorkingCopyPoolTest.java b/scm-core/src/test/java/sonia/scm/repository/work/CachingAllWorkingCopyPoolTest.java index 3c378acea3..65c9d02a83 100644 --- a/scm-core/src/test/java/sonia/scm/repository/work/CachingAllWorkingCopyPoolTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/work/CachingAllWorkingCopyPoolTest.java @@ -54,15 +54,15 @@ class CachingAllWorkingCopyPoolTest { CachingAllWorkingCopyPool cachingAllWorkingCopyPool; @Mock - WorkingCopyContext workingCopyContext; + SimpleWorkingCopyFactory.WorkingCopyContext workingCopyContext; @BeforeEach void initContext() throws SimpleWorkingCopyFactory.ReclaimFailedException { lenient().when(workingCopyContext.initialize(any())) - .thenAnswer(invocationOnMock -> new WorkingCopyPool.ParentAndClone<>(null, null, invocationOnMock.getArgument(0, File.class))); + .thenAnswer(invocationOnMock -> new WorkingCopy<>(null, null, () -> {}, invocationOnMock.getArgument(0, File.class))); lenient().when(workingCopyContext.reclaim(any())) - .thenAnswer(invocationOnMock -> new WorkingCopyPool.ParentAndClone<>(null, null, invocationOnMock.getArgument(0, File.class))); + .thenAnswer(invocationOnMock -> new WorkingCopy<>(null, null, () -> {}, invocationOnMock.getArgument(0, File.class))); } @Test @@ -70,7 +70,7 @@ class CachingAllWorkingCopyPoolTest { when(workingCopyContext.getScmRepository()).thenReturn(REPOSITORY); when(workdirProvider.createNewWorkdir()).thenReturn(temp.toFile()); - WorkingCopyPool.ParentAndClone workdir = cachingAllWorkingCopyPool.getWorkingCopy(workingCopyContext); + WorkingCopy workdir = cachingAllWorkingCopyPool.getWorkingCopy(workingCopyContext); verify(workingCopyContext).initialize(temp.toFile()); } @@ -80,9 +80,9 @@ class CachingAllWorkingCopyPoolTest { when(workingCopyContext.getScmRepository()).thenReturn(REPOSITORY); when(workdirProvider.createNewWorkdir()).thenReturn(temp.toFile()); - WorkingCopyPool.ParentAndClone firstWorkdir = cachingAllWorkingCopyPool.getWorkingCopy(workingCopyContext); + WorkingCopy firstWorkdir = cachingAllWorkingCopyPool.getWorkingCopy(workingCopyContext); cachingAllWorkingCopyPool.contextClosed(workingCopyContext, firstWorkdir.getDirectory()); - WorkingCopyPool.ParentAndClone secondWorkdir = cachingAllWorkingCopyPool.getWorkingCopy(workingCopyContext); + WorkingCopy secondWorkdir = cachingAllWorkingCopyPool.getWorkingCopy(workingCopyContext); verify(workingCopyContext).initialize(temp.toFile()); verify(workingCopyContext).reclaim(temp.toFile()); @@ -100,8 +100,8 @@ class CachingAllWorkingCopyPoolTest { firstDirectory, secondDirectory); - WorkingCopyPool.ParentAndClone firstWorkdir = cachingAllWorkingCopyPool.getWorkingCopy(workingCopyContext); - WorkingCopyPool.ParentAndClone secondWorkdir = cachingAllWorkingCopyPool.getWorkingCopy(workingCopyContext); + WorkingCopy firstWorkdir = cachingAllWorkingCopyPool.getWorkingCopy(workingCopyContext); + WorkingCopy secondWorkdir = cachingAllWorkingCopyPool.getWorkingCopy(workingCopyContext); cachingAllWorkingCopyPool.contextClosed(workingCopyContext, firstWorkdir.getDirectory()); cachingAllWorkingCopyPool.contextClosed(workingCopyContext, secondWorkdir.getDirectory()); diff --git a/scm-core/src/test/java/sonia/scm/repository/work/SimpleWorkingCopyFactoryTest.java b/scm-core/src/test/java/sonia/scm/repository/work/SimpleWorkingCopyFactoryTest.java index b3e2cb5e07..69a4225b22 100644 --- a/scm-core/src/test/java/sonia/scm/repository/work/SimpleWorkingCopyFactoryTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/work/SimpleWorkingCopyFactoryTest.java @@ -61,13 +61,13 @@ public class SimpleWorkingCopyFactoryTest { WorkdirProvider workdirProvider = new WorkdirProvider(temporaryFolder.newFolder()); WorkingCopyPool configurableTestWorkingCopyPool = new WorkingCopyPool() { @Override - public ParentAndClone getWorkingCopy(WorkingCopyContext context) { + public WorkingCopy getWorkingCopy(SimpleWorkingCopyFactory.WorkingCopyContext context) { workdir = workdirProvider.createNewWorkdir(); return context.initialize(workdir); } @Override - public void contextClosed(WorkingCopyContext createWorkdirContext, File workdir) { + public void contextClosed(SimpleWorkingCopyFactory.WorkingCopyContext createWorkdirContext, File workdir) { if (!workdirIsCached) { IOUtil.deleteSilently(workdir); } @@ -98,7 +98,7 @@ public class SimpleWorkingCopyFactoryTest { protected WorkingCopyInitializer getInitializer(Context context) { return (target, initialBranch) -> { initialBranchForLastCloneCall = initialBranch; - return new WorkingCopyPool.ParentAndClone<>(parent, clone, target); + return new ParentAndClone<>(parent, clone, target); }; } }; diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitWorkingCopyInitializer.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitWorkingCopyInitializer.java index 304a8893f9..e1cd889d07 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitWorkingCopyInitializer.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitWorkingCopyInitializer.java @@ -33,7 +33,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sonia.scm.repository.InternalRepositoryException; import sonia.scm.repository.work.SimpleWorkingCopyFactory; -import sonia.scm.repository.work.WorkingCopyPool; +import sonia.scm.repository.work.SimpleWorkingCopyFactory.ParentAndClone; import java.io.File; import java.io.IOException; @@ -54,7 +54,7 @@ class GitWorkingCopyInitializer implements SimpleWorkingCopyFactory.WorkingCopyI } @Override - public WorkingCopyPool.ParentAndClone initialize(File target, String initialBranch) { + public ParentAndClone initialize(File target, String initialBranch) { LOG.trace("clone repository {}", context.getRepository().getId()); long start = System.nanoTime(); try { @@ -71,7 +71,7 @@ class GitWorkingCopyInitializer implements SimpleWorkingCopyFactory.WorkingCopyI throw notFound(entity("Branch", initialBranch).in(context.getRepository())); } - return new WorkingCopyPool.ParentAndClone<>(null, clone, target); + return new ParentAndClone<>(null, clone, target); } catch (GitAPIException | IOException e) { throw new InternalRepositoryException(context.getRepository(), "could not clone working copy of repository", e); } finally { diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitWorkingCopyReclaimer.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitWorkingCopyReclaimer.java index 95d6b8a09b..2cd37432b6 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitWorkingCopyReclaimer.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitWorkingCopyReclaimer.java @@ -32,7 +32,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sonia.scm.repository.GitUtil; import sonia.scm.repository.work.SimpleWorkingCopyFactory; -import sonia.scm.repository.work.WorkingCopyPool; +import sonia.scm.repository.work.SimpleWorkingCopyFactory.ParentAndClone; import java.io.File; import java.io.IOException; @@ -48,7 +48,7 @@ class GitWorkingCopyReclaimer implements SimpleWorkingCopyFactory.WorkingCopyRec } @Override - public WorkingCopyPool.ParentAndClone reclaim(File target, String initialBranch) throws SimpleWorkingCopyFactory.ReclaimFailedException { + public ParentAndClone reclaim(File target, String initialBranch) throws SimpleWorkingCopyFactory.ReclaimFailedException { LOG.trace("reclaim repository {}", context.getRepository().getId()); long start = System.nanoTime(); Repository repo = openTarget(target); @@ -59,7 +59,7 @@ class GitWorkingCopyReclaimer implements SimpleWorkingCopyFactory.WorkingCopyRec git.checkout().setForced(true).setName("origin/" + initialBranch).call(); git.branchDelete().setBranchNames(initialBranch).setForce(true).call(); git.checkout().setName(initialBranch).setCreateBranch(true).call(); - return new WorkingCopyPool.ParentAndClone<>(null, repo, target); + return new ParentAndClone<>(null, repo, target); } catch (GitAPIException | IOException e) { throw new SimpleWorkingCopyFactory.ReclaimFailedException(e); } finally { diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactory.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactory.java index 364c64ed69..7fdd107ae0 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactory.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactory.java @@ -35,7 +35,6 @@ import com.aragost.javahg.commands.flags.CloneCommandFlags; import sonia.scm.repository.InternalRepositoryException; import sonia.scm.repository.work.SimpleWorkingCopyFactory; import sonia.scm.repository.work.WorkingCopyPool; -import sonia.scm.repository.work.WorkingCopyPool.ParentAndClone; import sonia.scm.util.IOUtil; import sonia.scm.web.HgRepositoryEnvironmentBuilder; diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnWorkingCopyInitializer.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnWorkingCopyInitializer.java index 2bb5ed6fc7..ed778f503f 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnWorkingCopyInitializer.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnWorkingCopyInitializer.java @@ -31,7 +31,7 @@ import org.tmatesoft.svn.core.wc2.SvnOperationFactory; import org.tmatesoft.svn.core.wc2.SvnTarget; import sonia.scm.repository.InternalRepositoryException; import sonia.scm.repository.work.SimpleWorkingCopyFactory; -import sonia.scm.repository.work.WorkingCopyPool; +import sonia.scm.repository.work.SimpleWorkingCopyFactory.ParentAndClone; import java.io.File; @@ -43,7 +43,7 @@ class SvnWorkingCopyInitializer implements SimpleWorkingCopyFactory.WorkingCopyI } @Override - public WorkingCopyPool.ParentAndClone initialize(File workingCopy, String initialBranch) { + public ParentAndClone initialize(File workingCopy, String initialBranch) { final SvnOperationFactory svnOperationFactory = new SvnOperationFactory(); SVNURL source; @@ -64,6 +64,6 @@ class SvnWorkingCopyInitializer implements SimpleWorkingCopyFactory.WorkingCopyI svnOperationFactory.dispose(); } - return new WorkingCopyPool.ParentAndClone<>(context.getDirectory(), workingCopy, workingCopy); + return new ParentAndClone<>(context.getDirectory(), workingCopy, workingCopy); } } diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnWorkingCopyReclaimer.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnWorkingCopyReclaimer.java index 9ed5c6006f..2e60ce4c52 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnWorkingCopyReclaimer.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnWorkingCopyReclaimer.java @@ -28,7 +28,7 @@ import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.wc.SVNClientManager; import org.tmatesoft.svn.core.wc.SVNRevision; import sonia.scm.repository.work.SimpleWorkingCopyFactory; -import sonia.scm.repository.work.WorkingCopyPool; +import sonia.scm.repository.work.SimpleWorkingCopyFactory.ParentAndClone; import java.io.File; @@ -42,7 +42,7 @@ class SvnWorkingCopyReclaimer implements SimpleWorkingCopyFactory.WorkingCopyRec } @Override - public WorkingCopyPool.ParentAndClone reclaim(File target, String initialBranch) throws SimpleWorkingCopyFactory.ReclaimFailedException { + public ParentAndClone reclaim(File target, String initialBranch) throws SimpleWorkingCopyFactory.ReclaimFailedException { SVNClientManager clientManager = SVNClientManager.newInstance(); try { clientManager.getWCClient().doRevert(new File[] {target}, INFINITY, null); @@ -51,6 +51,6 @@ class SvnWorkingCopyReclaimer implements SimpleWorkingCopyFactory.WorkingCopyRec } catch (SVNException e) { throw new SimpleWorkingCopyFactory.ReclaimFailedException(e); } - return new WorkingCopyPool.ParentAndClone<>(context.getDirectory(), target, target); + return new ParentAndClone<>(context.getDirectory(), target, target); } } From 77d67843863f775410b26794178247779b69c56c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Thu, 14 May 2020 23:30:26 +0200 Subject: [PATCH 24/29] Remove unnecessary interfaces --- .../work/SimpleWorkingCopyFactory.java | 22 ++----- .../work/SimpleWorkingCopyFactoryTest.java | 19 +++--- .../spi/GitWorkingCopyInitializer.java | 4 +- .../spi/GitWorkingCopyReclaimer.java | 3 +- .../spi/SimpleGitWorkingCopyFactory.java | 14 ++--- .../spi/SimpleGitWorkingCopyFactoryTest.java | 10 ++-- .../spi/SimpleHgWorkingCopyFactory.java | 58 +++++++++---------- .../spi/SimpleSvnWorkingCopyFactory.java | 10 ++-- .../spi/SvnWorkingCopyInitializer.java | 6 +- .../spi/SvnWorkingCopyReclaimer.java | 5 +- 10 files changed, 62 insertions(+), 89 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/repository/work/SimpleWorkingCopyFactory.java b/scm-core/src/main/java/sonia/scm/repository/work/SimpleWorkingCopyFactory.java index 7ed74c4e11..0b842ad78c 100644 --- a/scm-core/src/main/java/sonia/scm/repository/work/SimpleWorkingCopyFactory.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/SimpleWorkingCopyFactory.java @@ -41,10 +41,10 @@ import java.io.File; * implemented: * *
- *
{@link #getInitializer(C)}
+ *
{@link #initialize(C, File, String)}
*
Creates a new clone of the repository for the given context in the given * directory with the given branch checked out (if branches are supported).
- *
{@link #getReclaimer(C)}
+ *
{@link #reclaim(C, File, String)}
*
Reclaim the working directory with a already checked out clone of the * repository given in the context, so that the directory is not modified in * respect to the repository and the given branch is checked out (if branches @@ -215,19 +215,9 @@ public abstract class SimpleWorkingCopyFactory { - ParentAndClone initialize(File target, String initialBranch); - } + protected abstract ParentAndClone initialize(C context, File target, String initialBranch); - @FunctionalInterface - public interface WorkingCopyReclaimer { - ParentAndClone reclaim(File target, String initialBranch) throws ReclaimFailedException; - } - - protected abstract WorkingCopyInitializer getInitializer(C context); - - protected abstract WorkingCopyReclaimer getReclaimer(C context); + protected abstract ParentAndClone reclaim(C context, File target, String initialBranch) throws ReclaimFailedException; @SuppressWarnings("squid:S00112") // We do allow implementations to throw arbitrary exceptions here, so that we can handle them in closeCentral @@ -289,11 +279,11 @@ public abstract class SimpleWorkingCopyFactory reclaim(File workdir) throws SimpleWorkingCopyFactory.ReclaimFailedException { - return createWorkingCopyFromParentAndClone(getReclaimer(repositoryContext).reclaim(workdir, requestedBranch)); + return createWorkingCopyFromParentAndClone(SimpleWorkingCopyFactory.this.reclaim(repositoryContext, workdir, requestedBranch)); } public WorkingCopy initialize(File workdir) { - return createWorkingCopyFromParentAndClone(getInitializer(repositoryContext).initialize(workdir, requestedBranch)); + return createWorkingCopyFromParentAndClone(SimpleWorkingCopyFactory.this.initialize(repositoryContext, workdir, requestedBranch)); } public WorkingCopy createWorkingCopyFromParentAndClone(ParentAndClone parentAndClone) { diff --git a/scm-core/src/test/java/sonia/scm/repository/work/SimpleWorkingCopyFactoryTest.java b/scm-core/src/test/java/sonia/scm/repository/work/SimpleWorkingCopyFactoryTest.java index 69a4225b22..1ab22972f9 100644 --- a/scm-core/src/test/java/sonia/scm/repository/work/SimpleWorkingCopyFactoryTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/work/SimpleWorkingCopyFactoryTest.java @@ -84,23 +84,20 @@ public class SimpleWorkingCopyFactoryTest { } @Override - protected WorkingCopyReclaimer< - Closeable, Closeable> getReclaimer(Context context) { - return (target, initialBranch) -> {throw new UnsupportedOperationException();}; + protected ParentAndClone initialize(Context context, File target, String initialBranch) { + initialBranchForLastCloneCall = initialBranch; + return new ParentAndClone<>(parent, clone, target); + } + + @Override + protected ParentAndClone reclaim(Context context, File target, String initialBranch) throws ReclaimFailedException { + throw new UnsupportedOperationException(); } @Override protected void closeWorkingCopy(Closeable workingCopy) throws Exception { workingCopy.close(); } - - @Override - protected WorkingCopyInitializer getInitializer(Context context) { - return (target, initialBranch) -> { - initialBranchForLastCloneCall = initialBranch; - return new ParentAndClone<>(parent, clone, target); - }; - } }; } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitWorkingCopyInitializer.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitWorkingCopyInitializer.java index e1cd889d07..d48a64cc25 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitWorkingCopyInitializer.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitWorkingCopyInitializer.java @@ -32,7 +32,6 @@ import org.eclipse.jgit.lib.Repository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sonia.scm.repository.InternalRepositoryException; -import sonia.scm.repository.work.SimpleWorkingCopyFactory; import sonia.scm.repository.work.SimpleWorkingCopyFactory.ParentAndClone; import java.io.File; @@ -41,7 +40,7 @@ import java.io.IOException; import static sonia.scm.ContextEntry.ContextBuilder.entity; import static sonia.scm.NotFoundException.notFound; -class GitWorkingCopyInitializer implements SimpleWorkingCopyFactory.WorkingCopyInitializer { +class GitWorkingCopyInitializer { private static final Logger LOG = LoggerFactory.getLogger(GitWorkingCopyInitializer.class); @@ -53,7 +52,6 @@ class GitWorkingCopyInitializer implements SimpleWorkingCopyFactory.WorkingCopyI this.context = context; } - @Override public ParentAndClone initialize(File target, String initialBranch) { LOG.trace("clone repository {}", context.getRepository().getId()); long start = System.nanoTime(); diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitWorkingCopyReclaimer.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitWorkingCopyReclaimer.java index 2cd37432b6..c5ffd24aa7 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitWorkingCopyReclaimer.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitWorkingCopyReclaimer.java @@ -37,7 +37,7 @@ import sonia.scm.repository.work.SimpleWorkingCopyFactory.ParentAndClone; import java.io.File; import java.io.IOException; -class GitWorkingCopyReclaimer implements SimpleWorkingCopyFactory.WorkingCopyReclaimer { +class GitWorkingCopyReclaimer { private static final Logger LOG = LoggerFactory.getLogger(GitWorkingCopyReclaimer.class); @@ -47,7 +47,6 @@ class GitWorkingCopyReclaimer implements SimpleWorkingCopyFactory.WorkingCopyRec this.context = context; } - @Override public ParentAndClone reclaim(File target, String initialBranch) throws SimpleWorkingCopyFactory.ReclaimFailedException { LOG.trace("reclaim repository {}", context.getRepository().getId()); long start = System.nanoTime(); diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactory.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactory.java index 2de4ff92c0..a4fa38111e 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactory.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactory.java @@ -26,18 +26,14 @@ package sonia.scm.repository.spi; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.transport.ScmTransportProtocol; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import sonia.scm.repository.GitWorkingCopyFactory; -import sonia.scm.repository.work.WorkingCopyPool; import sonia.scm.repository.work.SimpleWorkingCopyFactory; +import sonia.scm.repository.work.WorkingCopyPool; import sonia.scm.util.SystemUtil; import javax.inject.Inject; import java.io.File; -import static sonia.scm.ContextEntry.ContextBuilder.entity; - public class SimpleGitWorkingCopyFactory extends SimpleWorkingCopyFactory implements GitWorkingCopyFactory { @Inject @@ -46,13 +42,13 @@ public class SimpleGitWorkingCopyFactory extends SimpleWorkingCopyFactory getInitializer(GitContext context) { - return new GitWorkingCopyInitializer(this, context); + public ParentAndClone initialize(GitContext context, File target, String initialBranch) { + return new GitWorkingCopyInitializer(this, context).initialize(target, initialBranch); } @Override - protected WorkingCopyReclaimer getReclaimer(GitContext context) { - return new GitWorkingCopyReclaimer(context); + public ParentAndClone reclaim(GitContext context, File target, String initialBranch) throws SimpleWorkingCopyFactory.ReclaimFailedException { + return new GitWorkingCopyReclaimer(context).reclaim(target, initialBranch); } String createScmTransportProtocolUri(File bareRepository) { diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactoryTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactoryTest.java index 93c1c1425b..9a32b5d01c 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactoryTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/SimpleGitWorkingCopyFactoryTest.java @@ -142,7 +142,7 @@ public class SimpleGitWorkingCopyFactoryTest extends AbstractGitCommandTestBase SimpleGitWorkingCopyFactory factory = new SimpleGitWorkingCopyFactory(new NoneCachingWorkingCopyPool(workdirProvider)); File workdir = createExistingClone(factory); - factory.getReclaimer(createContext()).reclaim(workdir, "master"); + factory.reclaim(createContext(), workdir, "master"); assertBranchCheckedOutAndClean(workdir, "master"); } @@ -152,7 +152,7 @@ public class SimpleGitWorkingCopyFactoryTest extends AbstractGitCommandTestBase SimpleGitWorkingCopyFactory factory = new SimpleGitWorkingCopyFactory(new NoneCachingWorkingCopyPool(workdirProvider)); File workdir = createExistingClone(factory); - factory.getReclaimer(createContext()).reclaim(workdir, "test-branch"); + factory.reclaim(createContext(), workdir, "test-branch"); assertBranchCheckedOutAndClean(workdir, "test-branch"); } @@ -163,7 +163,7 @@ public class SimpleGitWorkingCopyFactoryTest extends AbstractGitCommandTestBase File workdir = createExistingClone(factory); Git.open(workdir).rm().addFilepattern("a.txt").call(); - factory.getReclaimer(createContext()).reclaim(workdir, "master"); + factory.reclaim(createContext(), workdir, "master"); assertBranchCheckedOutAndClean(workdir, "master"); } @@ -174,7 +174,7 @@ public class SimpleGitWorkingCopyFactoryTest extends AbstractGitCommandTestBase File workdir = createExistingClone(factory); Files.delete(workdir.toPath().resolve("a.txt")); - factory.getReclaimer(createContext()).reclaim(workdir, "master"); + factory.reclaim(createContext(), workdir, "master"); assertBranchCheckedOutAndClean(workdir, "master"); } @@ -187,7 +187,7 @@ public class SimpleGitWorkingCopyFactoryTest extends AbstractGitCommandTestBase Files.createDirectories(newDirectory); Files.createFile(newDirectory.resolve("newFile")); - factory.getReclaimer(createContext()).reclaim(workdir, "master"); + factory.reclaim(createContext(), workdir, "master"); assertBranchCheckedOutAndClean(workdir, "master"); } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactory.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactory.java index 7fdd107ae0..edd2e3aca1 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactory.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactory.java @@ -55,23 +55,36 @@ public class SimpleHgWorkingCopyFactory extends SimpleWorkingCopyFactory getInitializer(HgCommandContext context) { - return (target, initialBranch) -> { - Repository centralRepository = openCentral(context); - CloneCommand cloneCommand = CloneCommandFlags.on(centralRepository); - if (initialBranch != null) { - cloneCommand.updaterev(initialBranch); - } - try { - cloneCommand.execute(target.getAbsolutePath()); - } catch (IOException e) { - throw new InternalRepositoryException(context.getScmRepository(), "could not clone repository", e); - } + public ParentAndClone initialize(HgCommandContext context, File target, String initialBranch) { + Repository centralRepository = openCentral(context); + CloneCommand cloneCommand = CloneCommandFlags.on(centralRepository); + if (initialBranch != null) { + cloneCommand.updaterev(initialBranch); + } + try { + cloneCommand.execute(target.getAbsolutePath()); + } catch (IOException e) { + throw new InternalRepositoryException(context.getScmRepository(), "could not clone repository", e); + } + BaseRepository clone = Repository.open(target); + + return new ParentAndClone<>(centralRepository, clone, target); + } + + @Override + protected ParentAndClone reclaim(HgCommandContext context, File target, String initialBranch) throws ReclaimFailedException { + Repository centralRepository = openCentral(context); + try { BaseRepository clone = Repository.open(target); - + for (String unknown : StatusCommand.on(clone).execute().getUnknown()) { + delete(clone.getDirectory(), unknown); + } + UpdateCommand.on(clone).rev(initialBranch).clean().execute(); return new ParentAndClone<>(centralRepository, clone, target); - }; + } catch (ExecutionException | IOException e) { + throw new ReclaimFailedException(e); + } } public Repository openCentral(HgCommandContext context) { @@ -80,23 +93,6 @@ public class SimpleHgWorkingCopyFactory extends SimpleWorkingCopyFactory getReclaimer(HgCommandContext context) { - return (target, initialBranch) -> { - Repository centralRepository = openCentral(context); - try { - BaseRepository clone = Repository.open(target); - for (String unknown : StatusCommand.on(clone).execute().getUnknown()) { - delete(clone.getDirectory(), unknown); - } - UpdateCommand.on(clone).rev(initialBranch).clean().execute(); - return new ParentAndClone<>(centralRepository, clone, target); - } catch (ExecutionException | IOException e) { - throw new ReclaimFailedException(e); - } - }; - } - private void delete(File directory, String unknownFile) throws IOException { IOUtil.delete(new File(directory, unknownFile)); } diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactory.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactory.java index 6156ad6cf5..e3a1bda34c 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactory.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactory.java @@ -25,8 +25,8 @@ package sonia.scm.repository.spi; import sonia.scm.repository.SvnWorkingCopyFactory; -import sonia.scm.repository.work.WorkingCopyPool; import sonia.scm.repository.work.SimpleWorkingCopyFactory; +import sonia.scm.repository.work.WorkingCopyPool; import javax.inject.Inject; import java.io.File; @@ -39,13 +39,13 @@ public class SimpleSvnWorkingCopyFactory extends SimpleWorkingCopyFactory getInitializer(SvnContext context) { - return new SvnWorkingCopyInitializer(context); + protected ParentAndClone initialize(SvnContext context, File workingCopy, String initialBranch) { + return new SvnWorkingCopyInitializer(context).initialize(workingCopy); } @Override - protected WorkingCopyReclaimer getReclaimer(SvnContext context) { - return new SvnWorkingCopyReclaimer(context); + protected ParentAndClone reclaim(SvnContext context, File target, String initialBranch) throws SimpleWorkingCopyFactory.ReclaimFailedException { + return new SvnWorkingCopyReclaimer(context).reclaim(target); } @Override diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnWorkingCopyInitializer.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnWorkingCopyInitializer.java index ed778f503f..140c7e10f3 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnWorkingCopyInitializer.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnWorkingCopyInitializer.java @@ -30,20 +30,18 @@ import org.tmatesoft.svn.core.wc2.SvnCheckout; import org.tmatesoft.svn.core.wc2.SvnOperationFactory; import org.tmatesoft.svn.core.wc2.SvnTarget; import sonia.scm.repository.InternalRepositoryException; -import sonia.scm.repository.work.SimpleWorkingCopyFactory; import sonia.scm.repository.work.SimpleWorkingCopyFactory.ParentAndClone; import java.io.File; -class SvnWorkingCopyInitializer implements SimpleWorkingCopyFactory.WorkingCopyInitializer { +class SvnWorkingCopyInitializer { private final SvnContext context; public SvnWorkingCopyInitializer(SvnContext context) { this.context = context; } - @Override - public ParentAndClone initialize(File workingCopy, String initialBranch) { + public ParentAndClone initialize(File workingCopy) { final SvnOperationFactory svnOperationFactory = new SvnOperationFactory(); SVNURL source; diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnWorkingCopyReclaimer.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnWorkingCopyReclaimer.java index 2e60ce4c52..f72efa8e8d 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnWorkingCopyReclaimer.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnWorkingCopyReclaimer.java @@ -34,15 +34,14 @@ import java.io.File; import static org.tmatesoft.svn.core.SVNDepth.INFINITY; -class SvnWorkingCopyReclaimer implements SimpleWorkingCopyFactory.WorkingCopyReclaimer { +class SvnWorkingCopyReclaimer { private final SvnContext context; public SvnWorkingCopyReclaimer(SvnContext context) { this.context = context; } - @Override - public ParentAndClone reclaim(File target, String initialBranch) throws SimpleWorkingCopyFactory.ReclaimFailedException { + public ParentAndClone reclaim(File target) throws SimpleWorkingCopyFactory.ReclaimFailedException { SVNClientManager clientManager = SVNClientManager.newInstance(); try { clientManager.getWCClient().doRevert(new File[] {target}, INFINITY, null); From 3a68e5ff2b37c633d5ebe3b60000fae4b3b9b089 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Sat, 16 May 2020 17:10:11 +0200 Subject: [PATCH 25/29] Rename class --- .../work/NoneCachingWorkingCopyPool.java | 6 ++++ ...java => SimpleCachingWorkingCopyPool.java} | 35 +++++++++++++++++-- ... => SimpleCachingWorkingCopyPoolTest.java} | 20 +++++------ .../spi/SimpleHgWorkingCopyFactoryTest.java | 4 +-- .../spi/SimpleSvnWorkingCopyFactoryTest.java | 6 ++-- 5 files changed, 53 insertions(+), 18 deletions(-) rename scm-core/src/main/java/sonia/scm/repository/work/{CachingAllWorkingCopyPool.java => SimpleCachingWorkingCopyPool.java} (64%) rename scm-core/src/test/java/sonia/scm/repository/work/{CachingAllWorkingCopyPoolTest.java => SimpleCachingWorkingCopyPoolTest.java} (82%) diff --git a/scm-core/src/main/java/sonia/scm/repository/work/NoneCachingWorkingCopyPool.java b/scm-core/src/main/java/sonia/scm/repository/work/NoneCachingWorkingCopyPool.java index 9e9859d27f..e5faa4935e 100644 --- a/scm-core/src/main/java/sonia/scm/repository/work/NoneCachingWorkingCopyPool.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/NoneCachingWorkingCopyPool.java @@ -29,6 +29,12 @@ import sonia.scm.util.IOUtil; import javax.inject.Inject; import java.io.File; +/** + * This is the default implementation for the {@link WorkingCopyPool}. For each requested {@link WorkingCopy} with + * {@link #getWorkingCopy(SimpleWorkingCopyFactory.WorkingCopyContext)}, a new directory is requested from the + * {@link WorkdirProvider}. This directory is deleted immediately when the context is closed with + * {@link #contextClosed(SimpleWorkingCopyFactory.WorkingCopyContext, File)}. + */ public class NoneCachingWorkingCopyPool implements WorkingCopyPool { private final WorkdirProvider workdirProvider; diff --git a/scm-core/src/main/java/sonia/scm/repository/work/CachingAllWorkingCopyPool.java b/scm-core/src/main/java/sonia/scm/repository/work/SimpleCachingWorkingCopyPool.java similarity index 64% rename from scm-core/src/main/java/sonia/scm/repository/work/CachingAllWorkingCopyPool.java rename to scm-core/src/main/java/sonia/scm/repository/work/SimpleCachingWorkingCopyPool.java index 190a7bb58a..7033d59772 100644 --- a/scm-core/src/main/java/sonia/scm/repository/work/CachingAllWorkingCopyPool.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/SimpleCachingWorkingCopyPool.java @@ -34,16 +34,45 @@ import java.io.File; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -public class CachingAllWorkingCopyPool implements WorkingCopyPool { +/** + * This class is a simple implementation of the {@link WorkingCopyPool} to demonstrate, + * how caching can work in the simplest way. For the first time a {@link WorkingCopy} is + * requested for a repository with {@link #getWorkingCopy(SimpleWorkingCopyFactory.WorkingCopyContext)}, + * this implementation fetches a new directory from the {@link WorkdirProvider}. + * On {@link #contextClosed(SimpleWorkingCopyFactory.WorkingCopyContext, File)}, + * the directory is not deleted, buy put into a map with the repository id as key. + * When a working copy is requested with {@link #getWorkingCopy(SimpleWorkingCopyFactory.WorkingCopyContext)} + * for a repository with such an existing directory, it is taken from the map, reclaimed and + * returned as {@link WorkingCopy}. + * If for one repository a working copy is requested, while another is in use already, + * a second directory is requested from the {@link WorkdirProvider} for the second one. + * If a context is closed with {@link #contextClosed(SimpleWorkingCopyFactory.WorkingCopyContext, File)} + * and there already is a directory stored in the map for the repository, + * the directory from the closed context simply is deleted. + *
+ * In general, this implementation should speed up things a bit, but one has to take into + * account, that there is no monitoring of diskspace. So you have to make sure, that + * there is enough space for a clone of each repository in the working dir. + *
+ * Possible enhancements: + *
    + *
  • Monitoring of times
  • + *
  • Allow multiple cached directories for busy repositories (possibly taking initial branches into account)
  • + *
  • Measure allocated disk space and set a limit
  • + *
  • Remove directories not used for a longer time
  • + *
  • Wait for a cached directory on parallel requests
  • + *
+ */ +public class SimpleCachingWorkingCopyPool implements WorkingCopyPool { - private static final Logger LOG = LoggerFactory.getLogger(CachingAllWorkingCopyPool.class); + private static final Logger LOG = LoggerFactory.getLogger(SimpleCachingWorkingCopyPool.class); private final Map workdirs = new ConcurrentHashMap<>(); private final WorkdirProvider workdirProvider; @Inject - public CachingAllWorkingCopyPool(WorkdirProvider workdirProvider) { + public SimpleCachingWorkingCopyPool(WorkdirProvider workdirProvider) { this.workdirProvider = workdirProvider; } diff --git a/scm-core/src/test/java/sonia/scm/repository/work/CachingAllWorkingCopyPoolTest.java b/scm-core/src/test/java/sonia/scm/repository/work/SimpleCachingWorkingCopyPoolTest.java similarity index 82% rename from scm-core/src/test/java/sonia/scm/repository/work/CachingAllWorkingCopyPoolTest.java rename to scm-core/src/test/java/sonia/scm/repository/work/SimpleCachingWorkingCopyPoolTest.java index 65c9d02a83..cc45936bb7 100644 --- a/scm-core/src/test/java/sonia/scm/repository/work/CachingAllWorkingCopyPoolTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/work/SimpleCachingWorkingCopyPoolTest.java @@ -44,14 +44,14 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @ExtendWith({MockitoExtension.class}) -class CachingAllWorkingCopyPoolTest { +class SimpleCachingWorkingCopyPoolTest { private static final Repository REPOSITORY = new Repository("1", "git", "space", "X"); @Mock WorkdirProvider workdirProvider; @InjectMocks - CachingAllWorkingCopyPool cachingAllWorkingCopyPool; + SimpleCachingWorkingCopyPool simpleCachingWorkingCopyPool; @Mock SimpleWorkingCopyFactory.WorkingCopyContext workingCopyContext; @@ -70,7 +70,7 @@ class CachingAllWorkingCopyPoolTest { when(workingCopyContext.getScmRepository()).thenReturn(REPOSITORY); when(workdirProvider.createNewWorkdir()).thenReturn(temp.toFile()); - WorkingCopy workdir = cachingAllWorkingCopyPool.getWorkingCopy(workingCopyContext); + WorkingCopy workdir = simpleCachingWorkingCopyPool.getWorkingCopy(workingCopyContext); verify(workingCopyContext).initialize(temp.toFile()); } @@ -80,9 +80,9 @@ class CachingAllWorkingCopyPoolTest { when(workingCopyContext.getScmRepository()).thenReturn(REPOSITORY); when(workdirProvider.createNewWorkdir()).thenReturn(temp.toFile()); - WorkingCopy firstWorkdir = cachingAllWorkingCopyPool.getWorkingCopy(workingCopyContext); - cachingAllWorkingCopyPool.contextClosed(workingCopyContext, firstWorkdir.getDirectory()); - WorkingCopy secondWorkdir = cachingAllWorkingCopyPool.getWorkingCopy(workingCopyContext); + WorkingCopy firstWorkdir = simpleCachingWorkingCopyPool.getWorkingCopy(workingCopyContext); + simpleCachingWorkingCopyPool.contextClosed(workingCopyContext, firstWorkdir.getDirectory()); + WorkingCopy secondWorkdir = simpleCachingWorkingCopyPool.getWorkingCopy(workingCopyContext); verify(workingCopyContext).initialize(temp.toFile()); verify(workingCopyContext).reclaim(temp.toFile()); @@ -100,10 +100,10 @@ class CachingAllWorkingCopyPoolTest { firstDirectory, secondDirectory); - WorkingCopy firstWorkdir = cachingAllWorkingCopyPool.getWorkingCopy(workingCopyContext); - WorkingCopy secondWorkdir = cachingAllWorkingCopyPool.getWorkingCopy(workingCopyContext); - cachingAllWorkingCopyPool.contextClosed(workingCopyContext, firstWorkdir.getDirectory()); - cachingAllWorkingCopyPool.contextClosed(workingCopyContext, secondWorkdir.getDirectory()); + WorkingCopy firstWorkdir = simpleCachingWorkingCopyPool.getWorkingCopy(workingCopyContext); + WorkingCopy secondWorkdir = simpleCachingWorkingCopyPool.getWorkingCopy(workingCopyContext); + simpleCachingWorkingCopyPool.contextClosed(workingCopyContext, firstWorkdir.getDirectory()); + simpleCachingWorkingCopyPool.contextClosed(workingCopyContext, secondWorkdir.getDirectory()); verify(workingCopyContext, never()).reclaim(any()); verify(workingCopyContext).initialize(firstDirectory); diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactoryTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactoryTest.java index 779b847087..8a8164e072 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactoryTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactoryTest.java @@ -32,7 +32,7 @@ import org.junit.Test; import org.junit.rules.TemporaryFolder; import sonia.scm.repository.HgHookManager; import sonia.scm.repository.HgTestUtil; -import sonia.scm.repository.work.CachingAllWorkingCopyPool; +import sonia.scm.repository.work.SimpleCachingWorkingCopyPool; import sonia.scm.repository.work.WorkdirProvider; import sonia.scm.repository.work.WorkingCopy; import sonia.scm.web.HgRepositoryEnvironmentBuilder; @@ -59,7 +59,7 @@ public class SimpleHgWorkingCopyFactoryTest extends AbstractHgCommandTestBase { workdirProvider = new WorkdirProvider(temporaryFolder.newFolder()); HgHookManager hookManager = HgTestUtil.createHookManager(); HgRepositoryEnvironmentBuilder environmentBuilder = new HgRepositoryEnvironmentBuilder(handler, hookManager); - workingCopyFactory = new SimpleHgWorkingCopyFactory(Providers.of(environmentBuilder), new CachingAllWorkingCopyPool(workdirProvider)) { + workingCopyFactory = new SimpleHgWorkingCopyFactory(Providers.of(environmentBuilder), new SimpleCachingWorkingCopyPool(workdirProvider)) { @Override public void configure(com.aragost.javahg.commands.PullCommand pullCommand) { // we do not want to configure http hooks in this unit test diff --git a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactoryTest.java b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactoryTest.java index d5fc3c70fe..1d7fcf2b54 100644 --- a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactoryTest.java +++ b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactoryTest.java @@ -29,7 +29,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.tmatesoft.svn.core.SVNException; -import sonia.scm.repository.work.CachingAllWorkingCopyPool; +import sonia.scm.repository.work.SimpleCachingWorkingCopyPool; import sonia.scm.repository.work.NoneCachingWorkingCopyPool; import sonia.scm.repository.work.WorkdirProvider; import sonia.scm.repository.work.WorkingCopy; @@ -95,7 +95,7 @@ public class SimpleSvnWorkingCopyFactoryTest extends AbstractSvnCommandTestBase @Test public void shouldDeleteUntrackedFileOnReclaim() throws IOException { - SimpleSvnWorkingCopyFactory factory = new SimpleSvnWorkingCopyFactory(new CachingAllWorkingCopyPool(workdirProvider)); + SimpleSvnWorkingCopyFactory factory = new SimpleSvnWorkingCopyFactory(new SimpleCachingWorkingCopyPool(workdirProvider)); WorkingCopy workingCopy = factory.createWorkingCopy(createContext(), null); File directory = workingCopy.getWorkingRepository(); @@ -113,7 +113,7 @@ public class SimpleSvnWorkingCopyFactoryTest extends AbstractSvnCommandTestBase @Test public void shouldRestoreDeletedFileOnReclaim() throws IOException { - SimpleSvnWorkingCopyFactory factory = new SimpleSvnWorkingCopyFactory(new CachingAllWorkingCopyPool(workdirProvider)); + SimpleSvnWorkingCopyFactory factory = new SimpleSvnWorkingCopyFactory(new SimpleCachingWorkingCopyPool(workdirProvider)); WorkingCopy workingCopy = factory.createWorkingCopy(createContext(), null); File directory = workingCopy.getWorkingRepository(); From d8af1ea8d0473f2684e1d5d30e368e72b1264a31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Sun, 17 May 2020 18:10:06 +0200 Subject: [PATCH 26/29] Test module --- .../modules/WorkingCopyPoolModule.java | 9 +- .../modules/WorkingCopyPoolModuleTest.java | 105 ++++++++++++++++++ 2 files changed, 110 insertions(+), 4 deletions(-) create mode 100644 scm-webapp/src/test/java/sonia/scm/lifecycle/modules/WorkingCopyPoolModuleTest.java diff --git a/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/WorkingCopyPoolModule.java b/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/WorkingCopyPoolModule.java index 63e9ce6cd4..209e8263d0 100644 --- a/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/WorkingCopyPoolModule.java +++ b/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/WorkingCopyPoolModule.java @@ -26,22 +26,23 @@ package sonia.scm.lifecycle.modules; import com.google.inject.AbstractModule; import sonia.scm.plugin.PluginLoader; +import sonia.scm.repository.work.NoneCachingWorkingCopyPool; import sonia.scm.repository.work.WorkingCopyPool; public class WorkingCopyPoolModule extends AbstractModule { - public static final String DEFAULT_WORKING_COPY_POOL_STRATEGY = "sonia.scm.repository.work.NoneCachingWorkingCopyPool"; + public static final String DEFAULT_WORKING_COPY_POOL_STRATEGY = NoneCachingWorkingCopyPool.class.getName(); public static final String WORKING_COPY_POOL_STRATEGY_PROPERTY = "scm.workingCopyPoolStrategy"; - private final PluginLoader pluginLoader; + private final ClassLoader classLoader; public WorkingCopyPoolModule(PluginLoader pluginLoader) { - this.pluginLoader = pluginLoader; + this.classLoader = pluginLoader.getUberClassLoader(); } @Override protected void configure() { String workingCopyPoolStrategy = System.getProperty(WORKING_COPY_POOL_STRATEGY_PROPERTY, DEFAULT_WORKING_COPY_POOL_STRATEGY); try { - Class strategyClass = (Class) pluginLoader.getUberClassLoader().loadClass(workingCopyPoolStrategy); + Class strategyClass = (Class) classLoader.loadClass(workingCopyPoolStrategy); bind(WorkingCopyPool.class).to(strategyClass); } catch (Exception e) { throw new RuntimeException("could not instantiate class for working copy pool: " + workingCopyPoolStrategy, e); diff --git a/scm-webapp/src/test/java/sonia/scm/lifecycle/modules/WorkingCopyPoolModuleTest.java b/scm-webapp/src/test/java/sonia/scm/lifecycle/modules/WorkingCopyPoolModuleTest.java new file mode 100644 index 0000000000..22797fa0ed --- /dev/null +++ b/scm-webapp/src/test/java/sonia/scm/lifecycle/modules/WorkingCopyPoolModuleTest.java @@ -0,0 +1,105 @@ +/* + * 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.lifecycle.modules; + +import com.google.inject.Binder; +import com.google.inject.binder.AnnotatedBindingBuilder; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import sonia.scm.plugin.PluginLoader; +import sonia.scm.repository.work.NoneCachingWorkingCopyPool; +import sonia.scm.repository.work.SimpleWorkingCopyFactory; +import sonia.scm.repository.work.WorkingCopy; +import sonia.scm.repository.work.WorkingCopyPool; + +import java.io.File; + +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static sonia.scm.lifecycle.modules.WorkingCopyPoolModule.WORKING_COPY_POOL_STRATEGY_PROPERTY; + +@ExtendWith(MockitoExtension.class) +class WorkingCopyPoolModuleTest { + + @Mock + PluginLoader pluginLoader; + @Mock + Binder binder; + @Mock + AnnotatedBindingBuilder bindingBuilder; + + @BeforeEach + void initClassLoader() { + lenient().when(pluginLoader.getUberClassLoader()).thenReturn(getClass().getClassLoader()); + } + + @AfterEach + void cleanProperty() { + System.clearProperty(WORKING_COPY_POOL_STRATEGY_PROPERTY); + } + + @Test + void shouldBindToDefaultWithoutProperty() { + System.clearProperty(WORKING_COPY_POOL_STRATEGY_PROPERTY); + WorkingCopyPoolModule module = new WorkingCopyPoolModule(pluginLoader); + when(binder.bind(WorkingCopyPool.class)).thenReturn(bindingBuilder); + + module.configure(binder); + + verify(bindingBuilder).to(NoneCachingWorkingCopyPool.class); + } + + @Test + void shouldBindToCustomPoolFromProperty() { + System.setProperty(WORKING_COPY_POOL_STRATEGY_PROPERTY, TestPool.class.getName()); + WorkingCopyPoolModule module = new WorkingCopyPoolModule(pluginLoader); + when(binder.bind(WorkingCopyPool.class)).thenReturn(bindingBuilder); + + module.configure(binder); + + verify(bindingBuilder).to(TestPool.class); + } + + static class TestPool implements WorkingCopyPool { + @Override + public WorkingCopy getWorkingCopy(SimpleWorkingCopyFactory.WorkingCopyContext context) { + return null; + } + + @Override + public void contextClosed(SimpleWorkingCopyFactory.WorkingCopyContext workingCopyContext, File workdir) { + + } + + @Override + public void shutdown() { + + } + } +} From 273bcb6f1aca9736ea29a5f7a068416d55962b50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Sun, 31 May 2020 14:21:37 +0200 Subject: [PATCH 27/29] Log changes --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3871922f1..4bb817d66e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Detect renamed files in git and hg diffs ([#1157](https://github.com/scm-manager/scm-manager/pull/1157)) - ClassLoader and Adapter parameters to typed store apis ([#1111](https://github.com/scm-manager/scm-manager/pull/1111)) - Native packaging for Debian, Red Hat, Windows, Unix, Docker and Kubernetes ([#1165](https://github.com/scm-manager/scm-manager/pull/1165)) +- Cache for working directories ([#1166](https://github.com/scm-manager/scm-manager/pull/1166)) ### Fixed - Correctly resolve Links in markdown files ([#1152](https://github.com/scm-manager/scm-manager/pull/1152)) From a32bd01c45265b732a553ff470e892cac22b81c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Tue, 2 Jun 2020 21:31:33 +0200 Subject: [PATCH 28/29] Fix peer review issues --- .../work/SimpleCachingWorkingCopyPool.java | 2 +- .../work/SimpleWorkingCopyFactory.java | 95 +----------------- .../SimpleWorkingCopyFactory_Sequence.png | Bin 0 -> 59594 bytes .../spi/GitWorkingCopyInitializer.java | 7 +- .../spi/GitWorkingCopyReclaimer.java | 7 +- .../modules/WorkingCopyPoolModule.java | 2 +- 6 files changed, 12 insertions(+), 101 deletions(-) create mode 100644 scm-core/src/main/java/sonia/scm/repository/work/doc-files/SimpleWorkingCopyFactory_Sequence.png diff --git a/scm-core/src/main/java/sonia/scm/repository/work/SimpleCachingWorkingCopyPool.java b/scm-core/src/main/java/sonia/scm/repository/work/SimpleCachingWorkingCopyPool.java index 7033d59772..1cb38a72f0 100644 --- a/scm-core/src/main/java/sonia/scm/repository/work/SimpleCachingWorkingCopyPool.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/SimpleCachingWorkingCopyPool.java @@ -40,7 +40,7 @@ import java.util.concurrent.ConcurrentHashMap; * requested for a repository with {@link #getWorkingCopy(SimpleWorkingCopyFactory.WorkingCopyContext)}, * this implementation fetches a new directory from the {@link WorkdirProvider}. * On {@link #contextClosed(SimpleWorkingCopyFactory.WorkingCopyContext, File)}, - * the directory is not deleted, buy put into a map with the repository id as key. + * the directory is not deleted, but put into a map with the repository id as key. * When a working copy is requested with {@link #getWorkingCopy(SimpleWorkingCopyFactory.WorkingCopyContext)} * for a repository with such an existing directory, it is taken from the map, reclaimed and * returned as {@link WorkingCopy}. diff --git a/scm-core/src/main/java/sonia/scm/repository/work/SimpleWorkingCopyFactory.java b/scm-core/src/main/java/sonia/scm/repository/work/SimpleWorkingCopyFactory.java index 0b842ad78c..0905ce1081 100644 --- a/scm-core/src/main/java/sonia/scm/repository/work/SimpleWorkingCopyFactory.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/SimpleWorkingCopyFactory.java @@ -55,97 +55,10 @@ import java.io.File; *
{@link #closeRepository(R)}
*
Closes resources allocated for the central repository.
*
- *
- *                     ┌─────────────┐          ┌───────────────────────────┐                                        ┌───────────────┐                                 ┌───────────────┐
- *                     │ModifyCommand│          │SimpleGitWorkingCopyFactory│                                        │WorkingCopyPool│                                 │WorkdirProvider│
- *                     └──────┬──────┘          └─────────────┬─────────────┘                                        └───────┬───────┘                                 └───────┬───────┘
- *                            │      createWorkingCopy        │                                                              │                                                 │
- *                            │──────────────────────────────>│                                                              │                                                 │
- *                            │                               │                                                              │                                                 │
- *                            │                               │        create          ┌──────────────────┐                  │                                                 │
- *                            │                               │──────────────────────> │WorkingCopyContext│                  │                                                 │
- *                            │                               │                        └────────┬─────────┘                  │                                                 │
- *                            │                               │                       getWorkingCopy                         │                                                 │
- *                            │                               │─────────────────────────────────────────────────────────────>│                                                 │
- *                            │                               │                                 │                            │                                                 │
- *                            │                               │                                 │                            │                                                 │
- *                            │                               │                                 │                            │                                                 │
- *                            │                               │                                 │                            │                                                 │
- *                            │                               │                                 │          reclaim           │                                                 │
- *                            │                               │                                 │ <──────────────────────────│                                                 │
- *                            │                               │                                 │                            │                                                 │
- *                            │                               │                                 │                            │                                                 │
- *                            │                               │              ╔══════╤═══════════╪════════════════════════════╪═════════════════════════════════════════════════╪═════════════════╗
- *                            │                               │              ║ ALT  │  reclaim successful                    │                                                 │                 ║
- *                            │                               │              ╟──────┘           │                            │                                                 │                 ║
- *                            │                               │              ║                  │                            │                  ┌───────────┐                  │                 ║
- *                            │                               │              ║                  │ ─────────────────────────────────────────────>│WorkingCopy│                  │                 ║
- *                            │                               │              ║                  │                            │                  └─────┬─────┘                  │                 ║
- *                            │                               │              ║                  │        WorkingCopy         │                                                 │                 ║
- *                            │                               │              ║                  │ ──────────────────────────>│                                                 │                 ║
- *                            │                               │              ╠══════════════════╪════════════════════════════╪═════════════════════════════════════════════════╪═════════════════╣
- *                            │                               │              ║ [reclaim fails; create new]                   │                                                 │                 ║
- *                            │                               │              ║                  │   ReclaimFailedException   │                                                 │                 ║
- *                            │                               │              ║                  │ ──────────────────────────>│                                                 │                 ║
- *                            │                               │              ║                  │                            │                                                 │                 ║
- *                            │                               │              ║                  │                            │                createNewWorkdir                 │                 ║
- *                            │                               │              ║                  │                            │────────────────────────────────────────────────>│                 ║
- *                            │                               │              ║                  │                            │                                                 │                 ║
- *                            │                               │              ║                  │                            │                                                 │                 ║
- *                            │                               │              ║                  │                            │<────────────────────────────────────────────────│                 ║
- *                            │                               │              ║                  │                            │                                                 │                 ║
- *                            │                               │              ║                  │         initialize         │                                                 │                 ║
- *                            │                               │              ║                  │ <──────────────────────────│                                                 │                 ║
- *                            │                               │              ║                  │                            │                                                 │                 ║
- *                            │                               │              ║                  │                            │                  ┌───────────┐                  │                 ║
- *                            │                               │              ║                  │ ─────────────────────────────────────────────>│WorkingCopy│                  │                 ║
- *                            │                               │              ║                  │                            │                  └─────┬─────┘                  │                 ║
- *                            │                               │              ║                  │        WorkingCopy         │                        │                        │                 ║
- *                            │                               │              ║                  │ ──────────────────────────>│                        │                        │                 ║
- *                            │                               │              ╚══════════════════╪════════════════════════════╪════════════════════════╪════════════════════════╪═════════════════╝
- *                            │                               │                                 │                            │                        │                        │
- *                            │                               │                         WorkingCopy                          │                        │                        │
- *                            │                               │<─────────────────────────────────────────────────────────────│                        │                        │
- *                            │                               │                                 │                            │                        │                        │
- *                            │         WorkingCopy           │                                 │                            │                        │                        │
- *                            │<──────────────────────────────│                                 │                            │                        │                        │
- *                            │                               │                                 │                            │                        │                        │
- *                            .                               .                                 .                            .                        .                        .
- *                            .                               .                                 .                            .                        .                        .
- *                            .                               .                                 .                            .                        .                        .
- *                            .                               .                                 .                            .                        .                        .
- *                            │                               │                        doWork   │                            │                        │                        │
- *                            │──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────>│                        │
- *                            │                               │                                 │                            │                        │                        │
- *                            .                               .                                 .                            .                        .                        .
- *                            .                               .                                 .                            .                        .                        .
- *                            .                               .                                 .                            .                        .                        .
- *                            .                               .                                 .                            .                        .                        .
- *                            │                               │                        close    │                            │                        │                        │
- *                            │──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────>│                        │
- *                            │                               │                                 │                            │                        │                        │
- *                            │                               │                                 │      close                 │                        │                        │
- *                            │                               │<──────────────────────────────────────────────────────────────────────────────────────│                        │
- *                            │                               │                                 │                            │                        │                        │
- *                            │                               ────┐                             │                            │                        │                        │
- *                            │                                   │ closeWorkingCopy            │                            │                        │                        │
- *                            │                               <───┘                             │                            │                        │                        │
- *                            │                               │                                 │                            │                        │                        │
- *                            │                               ────┐                             │                            │                        │                        │
- *                            │                                   │ closeRepository             │                            │                        │                        │
- *                            │                               <───┘                             │                            │                        │                        │
- *                            │                               │                                 │                            │                        │                        │
- *                            │                               │                        contextClosed                         │                        │                        │
- *                            │                               │─────────────────────────────────────────────────────────────>│                        │                        │
- *                            │                               │                                 │                            │                        │                        │
- *                            │                               │                                 │                            ────┐                    │                        │
- *                            │                               │                                 │                                │ cacheDirectory     │                        │
- *                            │                               │                                 │                            <───┘                    │                        │
- *                     ┌──────┴──────┐          ┌─────────────┴─────────────┐          ┌────────┴─────────┐          ┌───────┴───────┐          ┌─────┴─────┐          ┌───────┴───────┐
- *                     │ModifyCommand│          │SimpleGitWorkingCopyFactory│          │WorkingCopyContext│          │WorkingCopyPool│          │WorkingCopy│          │WorkdirProvider│
- *                     └─────────────┘          └───────────────────────────┘          └──────────────────┘          └───────────────┘          └───────────┘          └───────────────┘
- * 
- * + *
+ * The general process looks like this: + *
+ * * @param Type of central repository location * @param Type of working copy for repository * @param Type of repository context diff --git a/scm-core/src/main/java/sonia/scm/repository/work/doc-files/SimpleWorkingCopyFactory_Sequence.png b/scm-core/src/main/java/sonia/scm/repository/work/doc-files/SimpleWorkingCopyFactory_Sequence.png new file mode 100644 index 0000000000000000000000000000000000000000..6e9306bdddbbafc60fbd1dbe4be64c25a3f61e5f GIT binary patch literal 59594 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 literal 0 HcmV?d00001 diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitWorkingCopyInitializer.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitWorkingCopyInitializer.java index d48a64cc25..11019b288c 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitWorkingCopyInitializer.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitWorkingCopyInitializer.java @@ -24,6 +24,7 @@ package sonia.scm.repository.spi; +import com.google.common.base.Stopwatch; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.lib.Constants; @@ -54,7 +55,7 @@ class GitWorkingCopyInitializer { public ParentAndClone initialize(File target, String initialBranch) { LOG.trace("clone repository {}", context.getRepository().getId()); - long start = System.nanoTime(); + Stopwatch stopwatch = Stopwatch.createStarted(); try { Repository clone = Git.cloneRepository() .setURI(simpleGitWorkingCopyFactory.createScmTransportProtocolUri(context.getDirectory())) @@ -73,9 +74,7 @@ class GitWorkingCopyInitializer { } catch (GitAPIException | IOException e) { throw new InternalRepositoryException(context.getRepository(), "could not clone working copy of repository", e); } finally { - long end = System.nanoTime(); - long duration = end - start; - LOG.trace("took {} ns to clone repository {}", duration, context.getRepository().getId()); + LOG.trace("took {} to clone repository {}", stopwatch.stop(), context.getRepository().getId()); } } } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitWorkingCopyReclaimer.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitWorkingCopyReclaimer.java index c5ffd24aa7..3b605b531e 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitWorkingCopyReclaimer.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitWorkingCopyReclaimer.java @@ -24,6 +24,7 @@ package sonia.scm.repository.spi; +import com.google.common.base.Stopwatch; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.ResetCommand; import org.eclipse.jgit.api.errors.GitAPIException; @@ -49,7 +50,7 @@ class GitWorkingCopyReclaimer { public ParentAndClone reclaim(File target, String initialBranch) throws SimpleWorkingCopyFactory.ReclaimFailedException { LOG.trace("reclaim repository {}", context.getRepository().getId()); - long start = System.nanoTime(); + Stopwatch stopwatch = Stopwatch.createStarted(); Repository repo = openTarget(target); try (Git git = Git.open(target)) { git.reset().setMode(ResetCommand.ResetType.HARD).call(); @@ -62,9 +63,7 @@ class GitWorkingCopyReclaimer { } catch (GitAPIException | IOException e) { throw new SimpleWorkingCopyFactory.ReclaimFailedException(e); } finally { - long end = System.nanoTime(); - long duration = end - start; - LOG.trace("took {} ns to reclaim repository {}\n", duration, context.getRepository().getId()); + LOG.trace("took {} to reclaim repository {}", stopwatch.stop(), context.getRepository().getId()); } } diff --git a/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/WorkingCopyPoolModule.java b/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/WorkingCopyPoolModule.java index 209e8263d0..a6871b8b74 100644 --- a/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/WorkingCopyPoolModule.java +++ b/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/WorkingCopyPoolModule.java @@ -45,7 +45,7 @@ public class WorkingCopyPoolModule extends AbstractModule { Class strategyClass = (Class) classLoader.loadClass(workingCopyPoolStrategy); bind(WorkingCopyPool.class).to(strategyClass); } catch (Exception e) { - throw new RuntimeException("could not instantiate class for working copy pool: " + workingCopyPoolStrategy, e); + throw new IllegalStateException("could not instantiate class for working copy pool: " + workingCopyPoolStrategy, e); } } } From 8528c0cfc11b334a5bbe2f95b13ce215eadb52f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Tue, 2 Jun 2020 21:48:28 +0200 Subject: [PATCH 29/29] Fix sonar issues --- .../work/NoneCachingWorkingCopyPool.java | 1 + .../work/WorkdirCreationException.java | 42 +++++++++++++++++++ .../scm/repository/work/WorkdirProvider.java | 2 +- .../spi/SimpleHgWorkingCopyFactory.java | 2 + .../repository/spi/HgBranchCommandTest.java | 5 ++- .../spi/SimpleSvnWorkingCopyFactory.java | 2 + .../main/resources/locales/de/plugins.json | 4 ++ .../main/resources/locales/en/plugins.json | 4 ++ 8 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 scm-core/src/main/java/sonia/scm/repository/work/WorkdirCreationException.java diff --git a/scm-core/src/main/java/sonia/scm/repository/work/NoneCachingWorkingCopyPool.java b/scm-core/src/main/java/sonia/scm/repository/work/NoneCachingWorkingCopyPool.java index e5faa4935e..c7bea0fd80 100644 --- a/scm-core/src/main/java/sonia/scm/repository/work/NoneCachingWorkingCopyPool.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/NoneCachingWorkingCopyPool.java @@ -56,5 +56,6 @@ public class NoneCachingWorkingCopyPool implements WorkingCopyPool { @Override public void shutdown() { + // no caches, nothing to clean up :-) } } diff --git a/scm-core/src/main/java/sonia/scm/repository/work/WorkdirCreationException.java b/scm-core/src/main/java/sonia/scm/repository/work/WorkdirCreationException.java new file mode 100644 index 0000000000..df3bb93ff1 --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/repository/work/WorkdirCreationException.java @@ -0,0 +1,42 @@ +/* + * 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.repository.work; + +import sonia.scm.ContextEntry; +import sonia.scm.ExceptionWithContext; + +public class WorkdirCreationException extends ExceptionWithContext { + + public static final String CODE = "3tS0mjSoo1"; + + public WorkdirCreationException(String path, Exception cause) { + super(ContextEntry.ContextBuilder.entity("Path", path).build(), "Could not create directory " + path, cause); + } + + @Override + public String getCode() { + return CODE; + } +} diff --git a/scm-core/src/main/java/sonia/scm/repository/work/WorkdirProvider.java b/scm-core/src/main/java/sonia/scm/repository/work/WorkdirProvider.java index 7f511b8d74..ae6a5a6d5e 100644 --- a/scm-core/src/main/java/sonia/scm/repository/work/WorkdirProvider.java +++ b/scm-core/src/main/java/sonia/scm/repository/work/WorkdirProvider.java @@ -47,7 +47,7 @@ public class WorkdirProvider { try { return Files.createTempDirectory(rootDirectory.toPath(),"workdir").toFile(); } catch (IOException e) { - throw new RuntimeException("could not create temporary workdir", e); + throw new WorkdirCreationException(rootDirectory.toString(), e); } } } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactory.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactory.java index edd2e3aca1..4e4c4cf80c 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactory.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/SimpleHgWorkingCopyFactory.java @@ -73,6 +73,8 @@ public class SimpleHgWorkingCopyFactory extends SimpleWorkingCopyFactory reclaim(HgCommandContext context, File target, String initialBranch) throws ReclaimFailedException { Repository centralRepository = openCentral(context); try { diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgBranchCommandTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgBranchCommandTest.java index 0972f11e8f..f3a632fa59 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgBranchCommandTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgBranchCommandTest.java @@ -93,8 +93,9 @@ public class HgBranchCommandTest extends AbstractHgCommandTestBase { public void shouldThrowInternalRepositoryException() { String branchToBeClosed = "default"; - new HgBranchCommand(cmdContext, workingCopyFactory).deleteOrClose(branchToBeClosed); - assertThrows(InternalRepositoryException.class, () -> new HgBranchCommand(cmdContext, workingCopyFactory).deleteOrClose(branchToBeClosed)); + HgBranchCommand hgBranchCommand = new HgBranchCommand(cmdContext, workingCopyFactory); + hgBranchCommand.deleteOrClose(branchToBeClosed); + assertThrows(InternalRepositoryException.class, () -> hgBranchCommand.deleteOrClose(branchToBeClosed)); } private List readBranches() { diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactory.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactory.java index e3a1bda34c..a2996d4148 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactory.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SimpleSvnWorkingCopyFactory.java @@ -50,9 +50,11 @@ public class SimpleSvnWorkingCopyFactory extends SimpleWorkingCopyFactory