diff --git a/scm-core/src/main/java/sonia/scm/repository/AbstractSimpleRepositoryHandler.java b/scm-core/src/main/java/sonia/scm/repository/AbstractSimpleRepositoryHandler.java index 3e975b862a..aa243b2b39 100644 --- a/scm-core/src/main/java/sonia/scm/repository/AbstractSimpleRepositoryHandler.java +++ b/scm-core/src/main/java/sonia/scm/repository/AbstractSimpleRepositoryHandler.java @@ -82,7 +82,7 @@ public abstract class AbstractSimpleRepositoryHandler + * WARNING: The Locations provided with this class may not be used from the plugins to store any plugin specific files. + *

* Please use the {@link sonia.scm.store.DataStoreFactory } and the {@link sonia.scm.store.DataStore} classes to store data * Please use the {@link sonia.scm.store.BlobStoreFactory } and the {@link sonia.scm.store.BlobStore} classes to store binary files * Please use the {@link sonia.scm.store.ConfigurationStoreFactory} and the {@link sonia.scm.store.ConfigurationStore} classes to store configurations @@ -22,7 +21,7 @@ import java.io.IOException; */ public final class InitialRepositoryLocationResolver { - private static final String REPOSITORIES_DIRECTORY = "repositories"; + private static final String DEFAULT_REPOSITORY_PATH = "repositories"; public static final String REPOSITORIES_NATIVE_DIRECTORY = "data"; private SCMContextProvider context; private FileSystem fileSystem; @@ -34,25 +33,25 @@ public final class InitialRepositoryLocationResolver { this.fileSystem = fileSystem; } - public static File getNativeDirectory(File repositoriesDirectory, String repositoryId) { - return new File(repositoriesDirectory, repositoryId - .concat(File.separator) - .concat(REPOSITORIES_NATIVE_DIRECTORY)); - } - public File getBaseDirectory() { - return new File(context.getBaseDirectory(), REPOSITORIES_DIRECTORY); + return new File(context.getBaseDirectory(), DEFAULT_REPOSITORY_PATH); } - public File createDirectory(Repository repository) throws IOException { - File initialRepoFolder = getDirectory(repository); - fileSystem.create(initialRepoFolder); + public File createDirectory(Repository repository) { + File initialRepoFolder = getDirectory(getDefaultRepositoryPath(), repository); + try { + fileSystem.create(initialRepoFolder); + } catch (IOException e) { + throw new InternalRepositoryException(repository, "Cannot create repository directory for "+repository.getNamespaceAndName(), e); + } return initialRepoFolder; } - public File getDirectory(Repository repository) { - return new File(context.getBaseDirectory(), REPOSITORIES_DIRECTORY - .concat(File.separator) - .concat(repository.getId())); + public File getDirectory(String defaultRepositoryRelativePath, Repository repository) { + return new File(context.getBaseDirectory(), defaultRepositoryRelativePath + File.separator + repository.getId()); + } + + public String getDefaultRepositoryPath() { + return DEFAULT_REPOSITORY_PATH ; } } diff --git a/scm-core/src/main/java/sonia/scm/repository/PathBasedRepositoryDAO.java b/scm-core/src/main/java/sonia/scm/repository/PathBasedRepositoryDAO.java index 6a9007adc3..8898a9323b 100644 --- a/scm-core/src/main/java/sonia/scm/repository/PathBasedRepositoryDAO.java +++ b/scm-core/src/main/java/sonia/scm/repository/PathBasedRepositoryDAO.java @@ -11,10 +11,10 @@ import java.nio.file.Path; public interface PathBasedRepositoryDAO extends RepositoryDAO { /** - * get the current path of the repository + * get the current path of the repository or create it * * @param repository * @return the current path of the repository */ - Path getPath(Repository repository) throws RepositoryPathNotFoundException; + Path getPath(Repository repository) ; } diff --git a/scm-core/src/main/java/sonia/scm/repository/RepositoryLocationResolver.java b/scm-core/src/main/java/sonia/scm/repository/RepositoryLocationResolver.java index 5515c3eb88..2355e7c8b1 100644 --- a/scm-core/src/main/java/sonia/scm/repository/RepositoryLocationResolver.java +++ b/scm-core/src/main/java/sonia/scm/repository/RepositoryLocationResolver.java @@ -39,35 +39,19 @@ public class RepositoryLocationResolver { * @return the current repository directory from the dao or the initial directory if the repository does not exists * @throws IOException */ - public File getRepositoryDirectory(Repository repository) throws IOException { + public File getRepositoryDirectory(Repository repository){ if (repositoryDAO instanceof PathBasedRepositoryDAO) { PathBasedRepositoryDAO pathBasedRepositoryDAO = (PathBasedRepositoryDAO) repositoryDAO; - try { - return pathBasedRepositoryDAO.getPath(repository).toFile(); - } catch (RepositoryPathNotFoundException e) { - return createInitialDirectory(repository); - } + return pathBasedRepositoryDAO.getPath(repository).toFile(); } - return createInitialDirectory(repository); + return initialRepositoryLocationResolver.createDirectory(repository); } public File getInitialBaseDirectory() { return initialRepositoryLocationResolver.getBaseDirectory(); } - public File createInitialDirectory(Repository repository) throws IOException { - return initialRepositoryLocationResolver.createDirectory(repository); - } - - public File getInitialDirectory(Repository repository) { - return initialRepositoryLocationResolver.getDirectory(repository); - } - - public File getNativeDirectory(Repository repository) throws IOException { + public File getNativeDirectory(Repository repository) { return new File (getRepositoryDirectory(repository), REPOSITORIES_NATIVE_DIRECTORY); } - - public File getInitialNativeDirectory(Repository repository) { - return new File (getInitialDirectory(repository), REPOSITORIES_NATIVE_DIRECTORY); - } } diff --git a/scm-dao-xml/src/main/java/sonia/scm/repository/xml/RepositoryPath.java b/scm-dao-xml/src/main/java/sonia/scm/repository/xml/RepositoryPath.java index bf2d812e40..db57b228f9 100644 --- a/scm-dao-xml/src/main/java/sonia/scm/repository/xml/RepositoryPath.java +++ b/scm-dao-xml/src/main/java/sonia/scm/repository/xml/RepositoryPath.java @@ -21,6 +21,9 @@ public class RepositoryPath implements ModelObject { @XmlTransient private Repository repository; + @XmlTransient + private boolean toBeSynchronized; + /** * Needed from JAXB */ @@ -87,4 +90,12 @@ public class RepositoryPath implements ModelObject { public boolean isValid() { return StringUtils.isNotEmpty(path); } + + public boolean toBeSynchronized() { + return toBeSynchronized; + } + + public void setToBeSynchronized(boolean toBeSynchronized) { + this.toBeSynchronized = toBeSynchronized; + } } diff --git a/scm-dao-xml/src/main/java/sonia/scm/repository/xml/XmlRepositoryDAO.java b/scm-dao-xml/src/main/java/sonia/scm/repository/xml/XmlRepositoryDAO.java index eadf277dd3..308efe42b1 100644 --- a/scm-dao-xml/src/main/java/sonia/scm/repository/xml/XmlRepositoryDAO.java +++ b/scm-dao-xml/src/main/java/sonia/scm/repository/xml/XmlRepositoryDAO.java @@ -1,19 +1,19 @@ /** * Copyright (c) 2010, Sebastian Sdorra * All rights reserved. - * + *

* Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: - * + *

* 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. + * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. * 3. Neither the name of SCM-Manager; nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + *

* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -24,9 +24,8 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + *

* http://bitbucket.org/sdorra/scm-manager - * */ @@ -40,14 +39,14 @@ import sonia.scm.repository.InitialRepositoryLocationResolver; import sonia.scm.repository.NamespaceAndName; import sonia.scm.repository.PathBasedRepositoryDAO; import sonia.scm.repository.Repository; -import sonia.scm.repository.RepositoryPathNotFoundException; import sonia.scm.store.ConfigurationStoreFactory; import sonia.scm.xml.AbstractXmlDAO; +import java.io.File; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Collection; -import java.util.Optional; +import java.util.function.Supplier; /** * @author Sebastian Sdorra @@ -57,9 +56,6 @@ public class XmlRepositoryDAO extends AbstractXmlDAO implements PathBasedRepositoryDAO { - /** - * Field description - */ public static final String STORE_NAME = "repositories"; private InitialRepositoryLocationResolver initialRepositoryLocationResolver; @@ -95,14 +91,23 @@ public class XmlRepositoryDAO @Override public void modify(Repository repository) { + String path = getPath(repository).toString(); db.remove(repository.getId()); - add(repository); + RepositoryPath repositoryPath = new RepositoryPath(path, repository.getId(), repository.clone()); + repositoryPath.setToBeSynchronized(true); + add(repositoryPath); } @Override public void add(Repository repository) { - String path = initialRepositoryLocationResolver.getDirectory(repository).getAbsolutePath(); + String path = getPath(repository).toString(); + RepositoryPath repositoryPath = new RepositoryPath(path, repository.getId(), repository.clone()); + repositoryPath.setToBeSynchronized(true); + add(repositoryPath); + } + + public void add(RepositoryPath repositoryPath) { synchronized (store) { db.add(repositoryPath); storeDB(); @@ -145,15 +150,21 @@ public class XmlRepositoryDAO } @Override - public Path getPath(Repository repository) throws RepositoryPathNotFoundException { - Optional repositoryPath = db.getPaths().stream() + public Path getPath(Repository repository) { + return db.getPaths().stream() .filter(repoPath -> repoPath.getId().equals(repository.getId())) - .findFirst(); - if (!repositoryPath.isPresent()) { - throw new RepositoryPathNotFoundException(); - } else { + .findFirst() + .map(RepositoryPath::getPath) + .map(relativePath -> Paths.get(new File(initialRepositoryLocationResolver.getBaseDirectory(), relativePath).toURI())) + .orElseGet(createRepositoryPath(repository)); + } - return Paths.get(repositoryPath.get().getPath()); - } + private Supplier createRepositoryPath(Repository repository) { + return () -> { + if (db.getDefaultDirectory() == null) { + db.setDefaultDirectory(initialRepositoryLocationResolver.getDefaultRepositoryPath()); + } + return Paths.get(initialRepositoryLocationResolver.getDirectory(db.getDefaultDirectory(), repository).toURI()); + }; } } diff --git a/scm-dao-xml/src/main/java/sonia/scm/repository/xml/XmlRepositoryDatabase.java b/scm-dao-xml/src/main/java/sonia/scm/repository/xml/XmlRepositoryDatabase.java index bf08909378..447d4311eb 100644 --- a/scm-dao-xml/src/main/java/sonia/scm/repository/xml/XmlRepositoryDatabase.java +++ b/scm-dao-xml/src/main/java/sonia/scm/repository/xml/XmlRepositoryDatabase.java @@ -60,6 +60,8 @@ public class XmlRepositoryDatabase implements XmlDatabase { private Long lastModified; + private String defaultDirectory; + @XmlJavaTypeAdapter(XmlRepositoryMapAdapter.class) @XmlElement(name = "repositories") private Map repositoryPathMap = new LinkedHashMap<>(); @@ -200,4 +202,12 @@ public class XmlRepositoryDatabase implements XmlDatabase { { this.lastModified = lastModified; } + + public String getDefaultDirectory() { + return defaultDirectory; + } + + public void setDefaultDirectory(String defaultDirectory) { + this.defaultDirectory = defaultDirectory; + } } diff --git a/scm-dao-xml/src/main/java/sonia/scm/repository/xml/XmlRepositoryMapAdapter.java b/scm-dao-xml/src/main/java/sonia/scm/repository/xml/XmlRepositoryMapAdapter.java index 02d7dcff4d..d6f1faa124 100644 --- a/scm-dao-xml/src/main/java/sonia/scm/repository/xml/XmlRepositoryMapAdapter.java +++ b/scm-dao-xml/src/main/java/sonia/scm/repository/xml/XmlRepositoryMapAdapter.java @@ -62,11 +62,15 @@ public class XmlRepositoryMapAdapter extends XmlAdapter provider; RepositoryLocationResolver repositoryLocationResolver ; - private Path repoDir; @Override protected void checkDirectory(File directory) { @@ -84,17 +83,14 @@ public class HgRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase { @Override protected RepositoryHandler createRepositoryHandler(ConfigurationStoreFactory factory, - File directory) throws RepositoryPathNotFoundException { + File directory) { DefaultFileSystem fileSystem = new DefaultFileSystem(); - PathBasedRepositoryDAO repoDao = mock(PathBasedRepositoryDAO.class); repositoryLocationResolver = new RepositoryLocationResolver(repoDao, new InitialRepositoryLocationResolver(contextProvider,fileSystem)); HgRepositoryHandler handler = new HgRepositoryHandler(factory, new DefaultFileSystem(), new HgContextProvider(), repositoryLocationResolver); handler.init(contextProvider); - repoDir = directory.toPath(); - when(repoDao.getPath(any())).thenReturn(repoDir); HgTestUtil.checkForSkip(handler); return handler; @@ -110,8 +106,8 @@ public class HgRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase { hgConfig.setPythonBinary("python"); repositoryHandler.setConfig(hgConfig); - Repository repository = new Repository("id", "git", "Space", "Name"); + initRepository(); File path = repositoryHandler.getDirectory(repository); - assertEquals(repoDir.toString()+File.separator+InitialRepositoryLocationResolver.REPOSITORIES_NATIVE_DIRECTORY, path.getAbsolutePath()); + assertEquals(repoPath.toString()+File.separator+InitialRepositoryLocationResolver.REPOSITORIES_NATIVE_DIRECTORY, path.getAbsolutePath()); } } diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/HgTestUtil.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/HgTestUtil.java index 9c8f9747cf..33c762e4f7 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/HgTestUtil.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/HgTestUtil.java @@ -96,7 +96,7 @@ public final class HgTestUtil * * @return */ - public static HgRepositoryHandler createHandler(File directory) throws RepositoryPathNotFoundException { + public static HgRepositoryHandler createHandler(File directory) { TempSCMContextProvider context = (TempSCMContextProvider) SCMContext.getContext(); diff --git a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/SvnRepositoryHandlerTest.java b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/SvnRepositoryHandlerTest.java index 3c644056ca..3ccbfea056 100644 --- a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/SvnRepositoryHandlerTest.java +++ b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/SvnRepositoryHandlerTest.java @@ -74,7 +74,6 @@ public class SvnRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase { private HookEventFacade facade = new HookEventFacade(repositoryManagerProvider, hookContextFactory); RepositoryLocationResolver repositoryLocationResolver ; - private Path repoDir; @Override protected void checkDirectory(File directory) { @@ -91,18 +90,12 @@ public class SvnRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase { @Override protected RepositoryHandler createRepositoryHandler(ConfigurationStoreFactory factory, - File directory) throws RepositoryPathNotFoundException { - - + File directory) { DefaultFileSystem fileSystem = new DefaultFileSystem(); - PathBasedRepositoryDAO repoDao = mock(PathBasedRepositoryDAO.class); - repositoryLocationResolver = new RepositoryLocationResolver(repoDao, new InitialRepositoryLocationResolver(contextProvider,fileSystem)); SvnRepositoryHandler handler = new SvnRepositoryHandler(factory, new DefaultFileSystem(), null, repositoryLocationResolver); - repoDir = directory.toPath(); - when(repoDao.getPath(any())).thenReturn(repoDir); handler.init(contextProvider); SvnConfig config = new SvnConfig(); @@ -122,9 +115,8 @@ public class SvnRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase { SvnConfig svnConfig = new SvnConfig(); repositoryHandler.setConfig(svnConfig); - Repository repository = new Repository("id", "svn", "Space", "Name"); - + initRepository(); File path = repositoryHandler.getDirectory(repository); - assertEquals(repoDir.toString()+File.separator+InitialRepositoryLocationResolver.REPOSITORIES_NATIVE_DIRECTORY, path.getAbsolutePath()); + assertEquals(repoPath.toString()+File.separator+InitialRepositoryLocationResolver.REPOSITORIES_NATIVE_DIRECTORY, path.getAbsolutePath()); } } diff --git a/scm-test/src/main/java/sonia/scm/repository/SimpleRepositoryHandlerTestBase.java b/scm-test/src/main/java/sonia/scm/repository/SimpleRepositoryHandlerTestBase.java index 0118b88743..55b4109bc7 100644 --- a/scm-test/src/main/java/sonia/scm/repository/SimpleRepositoryHandlerTestBase.java +++ b/scm-test/src/main/java/sonia/scm/repository/SimpleRepositoryHandlerTestBase.java @@ -41,20 +41,26 @@ import sonia.scm.util.IOUtil; import java.io.File; import java.io.IOException; +import java.nio.file.Path; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; //~--- JDK imports ------------------------------------------------------------ /** - * * @author Sebastian Sdorra */ public abstract class SimpleRepositoryHandlerTestBase extends AbstractTestBase { + protected PathBasedRepositoryDAO repoDao = mock(PathBasedRepositoryDAO.class); + protected Path repoPath; + protected Repository repository; + protected abstract void checkDirectory(File directory); protected abstract RepositoryHandler createRepositoryHandler( @@ -67,7 +73,8 @@ public abstract class SimpleRepositoryHandlerTestBase extends AbstractTestBase { @Test public void testCreateResourcePath() { - Repository repository = createRepository(); + createRepository(); + String path = handler.createResourcePath(repository); assertNotNull(path); @@ -77,7 +84,7 @@ public abstract class SimpleRepositoryHandlerTestBase extends AbstractTestBase { @Test public void testDelete() { - Repository repository = createRepository(); + createRepository(); handler.delete(repository); @@ -102,19 +109,26 @@ public abstract class SimpleRepositoryHandlerTestBase extends AbstractTestBase { } private Repository createRepository() { - Repository repository = RepositoryTestData.createHeartOfGold(); + File nativeRepoDirectory = initRepository(); handler.create(repository); - File directory = new File(new File(baseDirectory, repository.getId()), InitialRepositoryLocationResolver.REPOSITORIES_NATIVE_DIRECTORY); - assertTrue(directory.exists()); - assertTrue(directory.isDirectory()); - checkDirectory(directory); + assertTrue(nativeRepoDirectory.exists()); + assertTrue(nativeRepoDirectory.isDirectory()); + checkDirectory(nativeRepoDirectory); return repository; } + protected File initRepository() { + repository = RepositoryTestData.createHeartOfGold(); + File repoDirectory = new File(baseDirectory, repository.getId()); + repoPath = repoDirectory.toPath(); + when(repoDao.getPath(repository)).thenReturn(repoPath); + return new File(repoDirectory, InitialRepositoryLocationResolver.REPOSITORIES_NATIVE_DIRECTORY); + } + protected File baseDirectory; private RepositoryHandler handler;