Cleanup svn on reclaim

This commit is contained in:
René Pfeuffer
2020-05-11 21:43:51 +02:00
parent b40861534c
commit 28824c37d3
4 changed files with 163 additions and 51 deletions

View File

@@ -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<File,
}
@Override
protected WorkingCopyInitializer getInitializer(SvnContext context) {
return (workingCopy, initialBranch) -> {
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<File, File> getInitializer(SvnContext context) {
return new SvnWorkingCopyInitializer(context);
}
@Override
protected WorkingCopyReclaimer<File, File> 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

View File

@@ -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<File, File> {
private final SvnContext context;
public SvnWorkingCopyInitializer(SvnContext context) {
this.context = context;
}
@Override
public WorkingCopyPool.ParentAndClone<File, File> 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);
}
}

View File

@@ -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<File, File> {
private final SvnContext context;
public SvnWorkingCopyReclaimer(SvnContext context) {
this.context = context;
}
@Override
public WorkingCopyPool.ParentAndClone<File, File> 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);
}
}

View File

@@ -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<File, File> 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<File, File> 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<File, File> 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();
}
}