modify metadata.xml only if needed

introduce a defaultRepositoryDirectory in the XmlRepositoryDatabase
Bugfix: modify repository with changed location
This commit is contained in:
Mohamed Karray
2018-11-21 12:01:13 +01:00
parent 01f45aaf8c
commit bb1c84ba24
14 changed files with 128 additions and 124 deletions

View File

@@ -82,7 +82,7 @@ public abstract class AbstractSimpleRepositoryHandler<C extends RepositoryConfig
@Override
public Repository create(Repository repository) {
File directory = repositoryLocationResolver.getInitialNativeDirectory(repository);
File directory = repositoryLocationResolver.getNativeDirectory(repository);
if (directory != null && directory.exists()) {
throw new AlreadyExistsException(repository);
}
@@ -122,11 +122,7 @@ public abstract class AbstractSimpleRepositoryHandler<C extends RepositoryConfig
@Override
public void delete(Repository repository) {
File directory = null;
try {
directory = repositoryLocationResolver.getRepositoryDirectory(repository);
} catch (IOException e) {
throw new InternalRepositoryException(repository, "Cannot get the repository directory");
}
try {
if (directory.exists()) {
fileSystem.destroy(directory);
@@ -157,11 +153,7 @@ public abstract class AbstractSimpleRepositoryHandler<C extends RepositoryConfig
public File getDirectory(Repository repository) {
File directory;
if (isConfigured()) {
try {
directory = repositoryLocationResolver.getNativeDirectory(repository);
} catch (IOException e) {
throw new ConfigurationException("Error on getting the current repository directory");
}
} else {
throw new ConfigurationException("RepositoryHandler is not configured");
}

View File

@@ -8,11 +8,10 @@ import java.io.File;
import java.io.IOException;
/**
*
* A Location Resolver for File based Repository Storage.
*
* WARNING: The Locations provided with this class may not be used from the plugins to store any plugin specific files.
*
* <p>
* <b>WARNING:</b> The Locations provided with this class may not be used from the plugins to store any plugin specific files.
* <p>
* 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);
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 ;
}
}

View File

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

View File

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

View File

@@ -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;
}
}

View File

@@ -1,10 +1,10 @@
/**
* Copyright (c) 2010, Sebastian Sdorra
* All rights reserved.
*
* <p>
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* <p>
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
@@ -13,7 +13,7 @@
* 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.
*
* <p>
* 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.
*
* <p>
* 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<Repository, XmlRepositoryDatabase>
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> 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<? extends Path> createRepositoryPath(Repository repository) {
return () -> {
if (db.getDefaultDirectory() == null) {
db.setDefaultDirectory(initialRepositoryLocationResolver.getDefaultRepositoryPath());
}
return Paths.get(initialRepositoryLocationResolver.getDirectory(db.getDefaultDirectory(), repository).toURI());
};
}
}

View File

@@ -60,6 +60,8 @@ public class XmlRepositoryDatabase implements XmlDatabase<RepositoryPath> {
private Long lastModified;
private String defaultDirectory;
@XmlJavaTypeAdapter(XmlRepositoryMapAdapter.class)
@XmlElement(name = "repositories")
private Map<String, RepositoryPath> repositoryPathMap = new LinkedHashMap<>();
@@ -200,4 +202,12 @@ public class XmlRepositoryDatabase implements XmlDatabase<RepositoryPath> {
{
this.lastModified = lastModified;
}
public String getDefaultDirectory() {
return defaultDirectory;
}
public void setDefaultDirectory(String defaultDirectory) {
this.defaultDirectory = defaultDirectory;
}
}

View File

@@ -62,11 +62,15 @@ public class XmlRepositoryMapAdapter extends XmlAdapter<XmlRepositoryList, Map<S
// marshall the repo_path/metadata.xml files
for (RepositoryPath repositoryPath : repositoryPaths.getRepositoryPaths()) {
if (repositoryPath.toBeSynchronized()) {
File dir = new File(repositoryPath.getPath());
if (!dir.exists()) {
IOUtil.mkdirs(dir);
}
marshaller.marshal(repositoryPath.getRepository(), getRepositoryMetadataFile(dir));
repositoryPath.setToBeSynchronized(false);
}
}
} catch (JAXBException ex) {
throw new StoreException("failed to marshall repository database", ex);

View File

@@ -63,7 +63,7 @@ public abstract class AbstractXmlDAO<I extends ModelObject,
* the logger for XmlGroupDAO
*/
private static final Logger logger =
LoggerFactory.getLogger(XmlGroupDAO.class);
LoggerFactory.getLogger(AbstractXmlDAO.class);
//~--- constructors ---------------------------------------------------------

View File

@@ -42,18 +42,13 @@ import sonia.scm.schedule.Scheduler;
import sonia.scm.store.ConfigurationStoreFactory;
import java.io.File;
import java.nio.file.Path;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
//~--- JDK imports ------------------------------------------------------------
/**
*
* @author Sebastian Sdorra
*/
@RunWith(MockitoJUnitRunner.class)
@@ -69,7 +64,7 @@ public class GitRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase {
private GitWorkdirFactory gitWorkdirFactory;
RepositoryLocationResolver repositoryLocationResolver;
private Path repoDir;
@Override
protected void checkDirectory(File directory) {
@@ -92,16 +87,13 @@ public class GitRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase {
@Override
protected RepositoryHandler createRepositoryHandler(ConfigurationStoreFactory factory,
File directory) throws RepositoryPathNotFoundException {
File directory) {
DefaultFileSystem fileSystem = new DefaultFileSystem();
PathBasedRepositoryDAO repoDao = mock(PathBasedRepositoryDAO.class);
InitialRepositoryLocationResolver initialRepositoryLocationResolver = new InitialRepositoryLocationResolver(contextProvider, fileSystem);
repositoryLocationResolver = new RepositoryLocationResolver(repoDao, initialRepositoryLocationResolver);
GitRepositoryHandler repositoryHandler = new GitRepositoryHandler(factory,
fileSystem, scheduler, repositoryLocationResolver, gitWorkdirFactory);
repoDir = directory.toPath();
when(repoDao.getPath(any())).thenReturn(repoDir);
repositoryHandler.init(contextProvider);
GitConfig config = new GitConfig();
@@ -116,15 +108,14 @@ public class GitRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase {
public void getDirectory() {
GitRepositoryHandler repositoryHandler = new GitRepositoryHandler(factory,
new DefaultFileSystem(), scheduler, repositoryLocationResolver, gitWorkdirFactory);
Repository repository = new Repository("id", "git", "Space", "Name");
GitConfig config = new GitConfig();
config.setDisabled(false);
config.setGcExpression("gc exp");
repositoryHandler.setConfig(config);
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());
}
}

View File

@@ -66,7 +66,6 @@ public class HgRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase {
private com.google.inject.Provider<HgContext> 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());
}
}

View File

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

View File

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

View File

@@ -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;