Java tutorial
/** * This file is part of git-as-svn. It is subject to the license terms * in the LICENSE file found in the top-level directory of this distribution * and at http://www.gnu.org/licenses/gpl-2.0.html. No part of git-as-svn, * including this file, may be copied, modified, propagated, or distributed * except according to the terms contained in the LICENSE file. */ package svnserver; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.internal.storage.file.FileRepository; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Repository; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.tmatesoft.sqljet.core.internal.SqlJetPagerJournalMode; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.auth.BasicAuthenticationManager; import org.tmatesoft.svn.core.internal.wc.DefaultSVNOptions; import org.tmatesoft.svn.core.internal.wc.SVNFileUtil; import org.tmatesoft.svn.core.internal.wc17.SVNWCContext; import org.tmatesoft.svn.core.io.SVNRepository; import org.tmatesoft.svn.core.io.SVNRepositoryFactory; import org.tmatesoft.svn.core.wc2.SvnOperationFactory; import svnserver.config.*; import svnserver.context.LocalContext; import svnserver.context.SharedContext; import svnserver.ext.gitlfs.storage.LfsStorageFactory; import svnserver.ext.gitlfs.storage.memory.LfsMemoryStorage; import svnserver.repository.VcsAccess; import svnserver.repository.VcsRepositoryMapping; import svnserver.repository.git.GitRepository; import svnserver.repository.git.push.GitPushEmbedded; import svnserver.repository.locks.PersistentLockFactory; import svnserver.repository.mapping.RepositoryListMapping; import svnserver.server.SvnServer; import svnserver.tester.SvnTester; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.UUID; /** * Test subversion server. * * @author Artem V. Navrotskiy <bozaro@users.noreply.github.com> */ public final class SvnTestServer implements SvnTester { @NotNull private static final Logger log = LoggerFactory.getLogger(SvnTestServer.class); @NotNull public static final String USER_NAME = "tester"; @NotNull public static final String USER_NAME_NO_MAIL = "nomail"; @NotNull public static final String REAL_NAME = "Test User"; @NotNull public static final String EMAIL = "foo@bar.org"; @NotNull public static final String PASSWORD = "passw0rd"; @NotNull private static final String TEST_BRANCH_PREFIX = "test_"; @NotNull private final String BIND_HOST = "127.0.0.2"; @NotNull private final File tempDirectory; @NotNull private final Repository repository; @NotNull private final String testBranch; @NotNull private final String prefix; @NotNull private final SvnServer server; @NotNull private final List<SvnOperationFactory> svnFactories = new ArrayList<>(); private final boolean safeBranch; private SvnTestServer(@NotNull Repository repository, @Nullable String branch, @NotNull String prefix, boolean safeBranch, @Nullable UserDBConfig userDBConfig, boolean anonymousRead) throws Exception { SVNFileUtil.setSleepForTimestamp(false); this.repository = repository; this.safeBranch = safeBranch; this.prefix = prefix; tempDirectory = TestHelper.createTempDir("git-as-svn"); final String srcBranch = branch == null ? repository.getBranch() : branch; if (safeBranch) { cleanupBranches(repository); testBranch = TEST_BRANCH_PREFIX + UUID.randomUUID().toString().replaceAll("-", "").substring(0, 8); new Git(repository).branchCreate().setName(testBranch).setStartPoint(srcBranch).call(); } else { testBranch = srcBranch; } final Config config = new Config(BIND_HOST, 0); config.setCompressionEnabled(false); config.setCacheConfig(new MemoryCacheConfig()); config.setRepositoryMapping(new TestRepositoryConfig(repository, testBranch, prefix, anonymousRead)); if (userDBConfig != null) { config.setUserDB(userDBConfig); } else { config.setUserDB(new LocalUserDBConfig(new LocalUserDBConfig.UserEntry[] { new LocalUserDBConfig.UserEntry(USER_NAME, REAL_NAME, EMAIL, PASSWORD), new LocalUserDBConfig.UserEntry(USER_NAME_NO_MAIL, REAL_NAME, null, PASSWORD), })); } config.getShared().add(context -> context.add(LfsStorageFactory.class, new LfsMemoryStorage.Factory())); server = new SvnServer(tempDirectory, config); server.start(); log.info("Temporary server started (url: {}, path: {}, branch: {} as {})", getUrl(), repository.getDirectory(), srcBranch, testBranch); log.info("Temporary directory: {}", tempDirectory); } private void cleanupBranches(Repository repository) { final List<String> branches = new ArrayList<>(); for (String ref : repository.getAllRefs().keySet()) { if (ref.startsWith(Constants.R_HEADS + TEST_BRANCH_PREFIX)) { branches.add(ref.substring(Constants.R_HEADS.length())); } } if (!branches.isEmpty()) { for (String branch : branches) { log.info("Cleanup branch: {}", branch); try { new Git(repository).branchDelete().setBranchNames(branch).setForce(true).call(); } catch (GitAPIException e) { log.error("Cleanup branch: " + branch, e); } } } } @NotNull public static SvnTestServer createEmpty() throws Exception { final String branch = "master"; return new SvnTestServer(TestHelper.emptyRepository(), branch, "", false, null, true); } @NotNull public static SvnTestServer createEmpty(@Nullable UserDBConfig userDBConfig, boolean anonymousRead) throws Exception { final String branch = "master"; return new SvnTestServer(TestHelper.emptyRepository(), branch, "", false, userDBConfig, anonymousRead); } @NotNull public static SvnTestServer createMasterRepository() throws Exception { return new SvnTestServer(new FileRepository(TestHelper.findGitPath()), null, "/master", true, null, true); } @Override @NotNull public SVNURL getUrl() throws SVNException { return SVNURL.create("svn", null, BIND_HOST, server.getPort(), prefix, true); } @NotNull public Repository getRepository() { return repository; } @NotNull public File getTempDirectory() { return tempDirectory; } public void shutdown(int millis) throws IOException, InterruptedException { server.shutdown(millis); } @Override public void close() throws Exception { shutdown(0); if (safeBranch) { new Git(repository).branchDelete().setBranchNames(testBranch).setForce(true).call(); } for (SvnOperationFactory factory : svnFactories) { factory.dispose(); } svnFactories.clear(); repository.close(); TestHelper.deleteDirectory(tempDirectory); } @NotNull public SvnOperationFactory createOperationFactory() { return createOperationFactory(USER_NAME, PASSWORD); } @NotNull public SvnOperationFactory createOperationFactory(@NotNull String userName, @NotNull String password) { final SVNWCContext wcContext = new SVNWCContext(new DefaultSVNOptions(getTempDirectory(), true), null); wcContext.setSqliteTemporaryDbInMemory(true); wcContext.setSqliteJournalMode(SqlJetPagerJournalMode.MEMORY); final SvnOperationFactory factory = new SvnOperationFactory(wcContext); factory.setAuthenticationManager(BasicAuthenticationManager.newInstance(userName, password.toCharArray())); svnFactories.add(factory); return factory; } @NotNull public SVNRepository openSvnRepository() throws SVNException { return openSvnRepository(USER_NAME, PASSWORD); } @NotNull public SVNRepository openSvnRepository(@NotNull String userName, @NotNull String password) throws SVNException { final SVNRepository repo = SVNRepositoryFactory.create(getUrl()); repo.setAuthenticationManager(BasicAuthenticationManager.newInstance(userName, password.toCharArray())); return repo; } public void startShutdown() throws IOException { server.startShutdown(); } @NotNull public SharedContext getContext() { return server.getContext(); } private static class TestRepositoryConfig implements RepositoryMappingConfig { @NotNull private final Repository repository; @NotNull private final String branch; @NotNull private final String prefix; private final boolean anonymousRead; public TestRepositoryConfig(@NotNull Repository repository, @NotNull String branch, @NotNull String prefix, boolean anonymousRead) { this.repository = repository; this.branch = branch; this.prefix = prefix; this.anonymousRead = anonymousRead; } @NotNull @Override public VcsRepositoryMapping create(@NotNull SharedContext context) throws IOException, SVNException { final LocalContext local = new LocalContext(context, "test"); final AclConfig aclConfig = new AclConfig(); aclConfig.setAnonymousRead(anonymousRead); local.add(VcsAccess.class, aclConfig.create(local)); return RepositoryListMapping.create(prefix, new GitRepository(local, repository, new GitPushEmbedded(local, "", "", ""), branch, true, new PersistentLockFactory(local))); } } }