mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-02 03:25:56 +01:00
Introduce cache layer for workdirs
This commit is contained in:
@@ -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 {
|
||||
<R, W, C> SimpleWorkdirFactory.ParentAndClone<R, W> getWorkdir(
|
||||
Repository scmRepository,
|
||||
String requestedBranch,
|
||||
C context,
|
||||
SimpleWorkdirFactory.WorkdirInitializer<R, W> initializer,
|
||||
SimpleWorkdirFactory.WorkdirReclaimer<R, W> reclaimer
|
||||
) throws IOException;
|
||||
|
||||
boolean cache(Repository repository, File target) throws IOException;
|
||||
}
|
||||
@@ -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<String, File> workdirs = new HashMap<>();
|
||||
|
||||
private final WorkdirProvider workdirProvider;
|
||||
|
||||
@Inject
|
||||
public CachingAllWorkdirProvider(WorkdirProvider workdirProvider) {
|
||||
this.workdirProvider = workdirProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R, W, C> SimpleWorkdirFactory.ParentAndClone<R, W> getWorkdir(Repository scmRepository, String requestedBranch, C context, SimpleWorkdirFactory.WorkdirInitializer<R, W> initializer, SimpleWorkdirFactory.WorkdirReclaimer<R, W> 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 <R, W> SimpleWorkdirFactory.ParentAndClone<R, W> createNewWorkdir(SimpleWorkdirFactory.WorkdirInitializer<R, W> 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;
|
||||
}
|
||||
}
|
||||
@@ -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 <R, W, C> SimpleWorkdirFactory.ParentAndClone<R, W> getWorkdir(Repository scmRepository, String requestedBranch, C context, SimpleWorkdirFactory.WorkdirInitializer<R, W> initializer, SimpleWorkdirFactory.WorkdirReclaimer<R, W> reclaimer) throws IOException {
|
||||
return initializer.initialize(workdirProvider.createNewWorkdir());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cache(Repository repository, File target) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -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<R, W, C> implements WorkdirFactory<R,
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SimpleWorkdirFactory.class);
|
||||
|
||||
private final WorkdirProvider workdirProvider;
|
||||
private final CacheSupportingWorkdirProvider workdirProvider;
|
||||
|
||||
public SimpleWorkdirFactory(WorkdirProvider workdirProvider) {
|
||||
public SimpleWorkdirFactory(CacheSupportingWorkdirProvider workdirProvider) {
|
||||
this.workdirProvider = workdirProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorkingCopy<R, W> createWorkingCopy(C context, String initialBranch) {
|
||||
try {
|
||||
File directory = workdirProvider.createNewWorkdir();
|
||||
ParentAndClone<R, W> parentAndClone = cloneRepository(context, directory, initialBranch);
|
||||
return new WorkingCopy<>(parentAndClone.getClone(), parentAndClone.getParent(), this::closeWorkdir, this::closeCentral, directory);
|
||||
ParentAndClone<R, W> parentAndClone = workdirProvider.getWorkdir(
|
||||
getScmRepository(context),
|
||||
initialBranch,
|
||||
context,
|
||||
newFolder -> cloneRepository(context, newFolder, initialBranch),
|
||||
cachedFolder -> reclaimRepository(context, cachedFolder, initialBranch)
|
||||
);
|
||||
return new WorkingCopy<R, W>(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<R, W> {
|
||||
ParentAndClone<R, W> initialize(File target) throws IOException;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface WorkdirReclaimer<R, W> {
|
||||
ParentAndClone<R, W> reclaim(File target) throws IOException, ReclaimFailedException;
|
||||
}
|
||||
|
||||
protected abstract Repository getScmRepository(C context);
|
||||
|
||||
@SuppressWarnings("squid:S00112")
|
||||
@@ -64,6 +86,8 @@ public abstract class SimpleWorkdirFactory<R, W, C> implements WorkdirFactory<R,
|
||||
|
||||
protected abstract ParentAndClone<R, W> cloneRepository(C context, File target, String initialBranch) throws IOException;
|
||||
|
||||
protected abstract ParentAndClone<R, W> 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<R, W, C> implements WorkdirFactory<R,
|
||||
protected static class ParentAndClone<R, W> {
|
||||
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<R, W, C> implements WorkdirFactory<R,
|
||||
public W getClone() {
|
||||
return clone;
|
||||
}
|
||||
|
||||
public File getDirectory() {
|
||||
return directory;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ReclaimFailedException extends Exception {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -67,9 +67,13 @@ public class WorkingCopy<R, W> 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Closeable, Closeable, Context>(workdirProvider) {
|
||||
CacheSupportingWorkdirProvider configurableTestWorkdirProvider = new CacheSupportingWorkdirProvider() {
|
||||
@Override
|
||||
public <R, W, C> SimpleWorkdirFactory.ParentAndClone<R, W> getWorkdir(Repository scmRepository, String requestedBranch, C context, SimpleWorkdirFactory.WorkdirInitializer<R, W> initializer, SimpleWorkdirFactory.WorkdirReclaimer<R, W> reclaimer) throws IOException {
|
||||
workdir = workdirProvider.createNewWorkdir();
|
||||
return initializer.initialize(workdir);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cache(Repository repository, File target) {
|
||||
return workdirIsCached;
|
||||
}
|
||||
};
|
||||
simpleWorkdirFactory = new SimpleWorkdirFactory<Closeable, Closeable, Context>(configurableTestWorkdirProvider) {
|
||||
@Override
|
||||
protected Repository getScmRepository(Context context) {
|
||||
return REPOSITORY;
|
||||
@@ -66,6 +81,11 @@ public class SimpleWorkdirFactoryTest {
|
||||
repository.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ParentAndClone<Closeable, Closeable> 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<Closeable, Closeable> 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<Closeable, Closeable> workingCopy = simpleWorkdirFactory.createWorkingCopy(context, null)) {}
|
||||
|
||||
assertThat(workdir).doesNotExist();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldNotDeleteWorkdirIfCached() {
|
||||
Context context = new Context();
|
||||
workdirIsCached = true;
|
||||
try (WorkingCopy<Closeable, Closeable> workingCopy = simpleWorkdirFactory.createWorkingCopy(context, null)) {}
|
||||
|
||||
assertThat(workdir).exists();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldPropagateInitialBranch() {
|
||||
Context context = new Context();
|
||||
|
||||
@@ -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<Repository, Repository, GitContext> implements GitWorkdirFactory {
|
||||
|
||||
@Inject
|
||||
public SimpleGitWorkdirFactory(WorkdirProvider workdirProvider) {
|
||||
public SimpleGitWorkdirFactory(CacheSupportingWorkdirProvider workdirProvider) {
|
||||
super(workdirProvider);
|
||||
}
|
||||
|
||||
@@ -66,12 +67,17 @@ public class SimpleGitWorkdirFactory extends SimpleWorkdirFactory<Repository, Re
|
||||
throw notFound(entity("Branch", initialBranch).in(context.getRepository()));
|
||||
}
|
||||
|
||||
return new ParentAndClone<>(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<Repository, Repository> 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("\\\\", "/");
|
||||
|
||||
@@ -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<Git> interceptor) {
|
||||
return new GitMergeCommand(createContext(), new SimpleGitWorkdirFactory(new WorkdirProvider())) {
|
||||
return new GitMergeCommand(createContext(), new SimpleGitWorkdirFactory(new NoneCachingWorkdirProvider(new WorkdirProvider()))) {
|
||||
@Override
|
||||
<R, W extends GitCloneWorker<R>> R inClone(Function<Git, W> workerSupplier, GitWorkdirFactory workdirFactory, String initialBranch) {
|
||||
Function<Git, W> interceptedWorkerSupplier = git -> {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<Repository, Repository> 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<Repository, Repository> 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<Repository, Repository> 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<Repository, Repository> 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<Repository, Repository> workingCopy = factory.createWorkingCopy(createContext(), null)) {
|
||||
|
||||
@@ -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<Repository, Rep
|
||||
private final Provider<HgRepositoryEnvironmentBuilder> hgRepositoryEnvironmentBuilder;
|
||||
|
||||
@Inject
|
||||
public SimpleHgWorkdirFactory(Provider<HgRepositoryEnvironmentBuilder> hgRepositoryEnvironmentBuilder, WorkdirProvider workdirProvider) {
|
||||
public SimpleHgWorkdirFactory(Provider<HgRepositoryEnvironmentBuilder> hgRepositoryEnvironmentBuilder, CacheSupportingWorkdirProvider workdirProvider) {
|
||||
super(workdirProvider);
|
||||
this.hgRepositoryEnvironmentBuilder = hgRepositoryEnvironmentBuilder;
|
||||
}
|
||||
@Override
|
||||
public ParentAndClone<Repository, Repository> cloneRepository(HgCommandContext context, File target, String initialBranch) throws IOException {
|
||||
BiConsumer<sonia.scm.repository.Repository, Map<String, String>> repositoryMapBiConsumer =
|
||||
(repository, environment) -> hgRepositoryEnvironmentBuilder.get().buildFor(repository, null, environment);
|
||||
Repository centralRepository = context.openWithSpecialEnvironment(repositoryMapBiConsumer);
|
||||
Repository centralRepository = openCentral(context);
|
||||
CloneCommand cloneCommand = CloneCommandFlags.on(centralRepository);
|
||||
if (initialBranch != null) {
|
||||
cloneCommand.updaterev(initialBranch);
|
||||
@@ -62,7 +60,20 @@ public class SimpleHgWorkdirFactory extends SimpleWorkdirFactory<Repository, Rep
|
||||
|
||||
BaseRepository clone = Repository.open(target);
|
||||
|
||||
return new ParentAndClone<>(centralRepository, clone);
|
||||
return new ParentAndClone<>(centralRepository, clone, target);
|
||||
}
|
||||
|
||||
public Repository openCentral(HgCommandContext context) {
|
||||
BiConsumer<sonia.scm.repository.Repository, Map<String, String>> repositoryMapBiConsumer =
|
||||
(repository, environment) -> hgRepositoryEnvironmentBuilder.get().buildFor(repository, null, environment);
|
||||
return context.openWithSpecialEnvironment(repositoryMapBiConsumer);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ParentAndClone<Repository, Repository> 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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<File, File, SvnContext> implements SvnWorkDirFactory {
|
||||
|
||||
@Inject
|
||||
public SimpleSvnWorkDirFactory(WorkdirProvider workdirProvider) {
|
||||
public SimpleSvnWorkDirFactory(CacheSupportingWorkdirProvider workdirProvider) {
|
||||
super(workdirProvider);
|
||||
}
|
||||
|
||||
@@ -73,7 +74,12 @@ public class SimpleSvnWorkDirFactory extends SimpleWorkdirFactory<File, File, Sv
|
||||
svnOperationFactory.dispose();
|
||||
}
|
||||
|
||||
return new ParentAndClone<>(context.getDirectory(), workingCopy);
|
||||
return new ParentAndClone<>(context.getDirectory(), workingCopy, workingCopy);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ParentAndClone<File, File> reclaimRepository(SvnContext context, File target, String initialBranch) throws IOException {
|
||||
return new ParentAndClone<>(context.getDirectory(), target, target);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -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<File, File> 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<File, File> 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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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<? extends CacheSupportingWorkdirProvider> strategyClass = (Class<? extends CacheSupportingWorkdirProvider>) pluginLoader.getUberClassLoader().loadClass(workdirCacheStrategy);
|
||||
bind(CacheSupportingWorkdirProvider.class).to(strategyClass);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user