From c35363b79ffc773e574c26e47a6c20d5bf82477a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 3 Jul 2019 07:48:06 +0200 Subject: [PATCH] Store repository id in git config for each repository This is needed after migration from v1 to v2 and is done in GitV1UpdateStep.java. Therefore we hat to make the 'forAllPaths' method in PathBasedRepositoryLocationResolver available in the interface of RepositoryLocationResolver. --- .../RepositoryLocationResolver.java | 9 +++ .../UpdateStepRepositoryMetadataAccess.java | 11 +++ .../scm/repository/xml/MetadataStore.java | 15 ++-- .../PathBasedRepositoryLocationResolver.java | 9 +-- .../xml/SingleRepositoryUpdateProcessor.java | 6 +- .../scm/repository/xml/XmlRepositoryDAO.java | 18 ++--- ...thBasedRepositoryLocationResolverTest.java | 2 +- .../repository/xml/XmlRepositoryDAOTest.java | 22 +++--- .../sonia/scm/repository/GitConfigHelper.java | 21 ++++++ .../scm/repository/GitRepositoryHandler.java | 8 +-- .../repository/update/GitV1UpdateStep.java | 70 +++++++++++++++++++ .../scm/repository/HgRepositoryHandler.java | 10 --- .../TempDirRepositoryLocationResolver.java | 6 ++ .../lifecycle/modules/BootstrapModule.java | 3 + 14 files changed, 158 insertions(+), 52 deletions(-) create mode 100644 scm-core/src/main/java/sonia/scm/update/UpdateStepRepositoryMetadataAccess.java create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitConfigHelper.java create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/update/GitV1UpdateStep.java 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 1b7da51c4c..bdd7a03d62 100644 --- a/scm-core/src/main/java/sonia/scm/repository/RepositoryLocationResolver.java +++ b/scm-core/src/main/java/sonia/scm/repository/RepositoryLocationResolver.java @@ -1,5 +1,7 @@ package sonia.scm.repository; +import java.util.function.BiConsumer; + public abstract class RepositoryLocationResolver { public abstract boolean supportsLocationType(Class type); @@ -35,5 +37,12 @@ public abstract class RepositoryLocationResolver { * @throws IllegalStateException when there already is a location for the given repository registered. */ void setLocation(String repositoryId, T location); + + /** + * Iterates all repository locations known to this resolver instance and calls the consumer giving the repository id + * and its location for each repository. + * @param consumer This callback will be called for each repository with the repository id and its location. + */ + void forAllLocations(BiConsumer consumer); } } diff --git a/scm-core/src/main/java/sonia/scm/update/UpdateStepRepositoryMetadataAccess.java b/scm-core/src/main/java/sonia/scm/update/UpdateStepRepositoryMetadataAccess.java new file mode 100644 index 0000000000..33afe9f76b --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/update/UpdateStepRepositoryMetadataAccess.java @@ -0,0 +1,11 @@ +package sonia.scm.update; + +import sonia.scm.repository.Repository; + +/** + * Use this in {@link sonia.scm.migration.UpdateStep}s only to read repository objects directly from locations given by + * {@link sonia.scm.repository.RepositoryLocationResolver}. + */ +public interface UpdateStepRepositoryMetadataAccess { + Repository read(T location); +} diff --git a/scm-dao-xml/src/main/java/sonia/scm/repository/xml/MetadataStore.java b/scm-dao-xml/src/main/java/sonia/scm/repository/xml/MetadataStore.java index 1f5f0e81b6..f22180ff9a 100644 --- a/scm-dao-xml/src/main/java/sonia/scm/repository/xml/MetadataStore.java +++ b/scm-dao-xml/src/main/java/sonia/scm/repository/xml/MetadataStore.java @@ -5,19 +5,21 @@ import org.slf4j.LoggerFactory; import sonia.scm.ContextEntry; import sonia.scm.repository.InternalRepositoryException; import sonia.scm.repository.Repository; +import sonia.scm.store.StoreConstants; +import sonia.scm.update.UpdateStepRepositoryMetadataAccess; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import java.nio.file.Path; -class MetadataStore { +public class MetadataStore implements UpdateStepRepositoryMetadataAccess { private static final Logger LOG = LoggerFactory.getLogger(MetadataStore.class); private final JAXBContext jaxbContext; - MetadataStore() { + public MetadataStore() { try { jaxbContext = JAXBContext.newInstance(Repository.class); } catch (JAXBException ex) { @@ -25,10 +27,10 @@ class MetadataStore { } } - Repository read(Path path) { + public Repository read(Path path) { LOG.trace("read repository metadata from {}", path); try { - return (Repository) jaxbContext.createUnmarshaller().unmarshal(path.toFile()); + return (Repository) jaxbContext.createUnmarshaller().unmarshal(resolveDataPath(path).toFile()); } catch (JAXBException ex) { throw new InternalRepositoryException( ContextEntry.ContextBuilder.entity(Path.class, path.toString()).build(), "failed read repository metadata", ex @@ -41,10 +43,13 @@ class MetadataStore { try { Marshaller marshaller = jaxbContext.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); - marshaller.marshal(repository, path.toFile()); + marshaller.marshal(repository, resolveDataPath(path).toFile()); } catch (JAXBException ex) { throw new InternalRepositoryException(repository, "failed write repository metadata", ex); } } + private Path resolveDataPath(Path repositoryPath) { + return repositoryPath.resolve(StoreConstants.REPOSITORY_METADATA.concat(StoreConstants.FILE_EXTENSION)); + } } diff --git a/scm-dao-xml/src/main/java/sonia/scm/repository/xml/PathBasedRepositoryLocationResolver.java b/scm-dao-xml/src/main/java/sonia/scm/repository/xml/PathBasedRepositoryLocationResolver.java index 81cf167071..8f667b0e65 100644 --- a/scm-dao-xml/src/main/java/sonia/scm/repository/xml/PathBasedRepositoryLocationResolver.java +++ b/scm-dao-xml/src/main/java/sonia/scm/repository/xml/PathBasedRepositoryLocationResolver.java @@ -94,6 +94,11 @@ public class PathBasedRepositoryLocationResolver extends BasicRepositoryLocation PathBasedRepositoryLocationResolver.this.setLocation(repositoryId, ((Path) location).toAbsolutePath()); } } + + @Override + public void forAllLocations(BiConsumer consumer) { + pathById.forEach((id, path) -> consumer.accept(id, (T) contextProvider.resolve(path))); + } }; } @@ -115,10 +120,6 @@ public class PathBasedRepositoryLocationResolver extends BasicRepositoryLocation return contextProvider.resolve(removedPath); } - void forAllPaths(BiConsumer consumer) { - pathById.forEach((id, path) -> consumer.accept(id, contextProvider.resolve(path))); - } - void updateModificationDate() { this.writePathDatabase(); } diff --git a/scm-dao-xml/src/main/java/sonia/scm/repository/xml/SingleRepositoryUpdateProcessor.java b/scm-dao-xml/src/main/java/sonia/scm/repository/xml/SingleRepositoryUpdateProcessor.java index eeb95f75b0..f963047624 100644 --- a/scm-dao-xml/src/main/java/sonia/scm/repository/xml/SingleRepositoryUpdateProcessor.java +++ b/scm-dao-xml/src/main/java/sonia/scm/repository/xml/SingleRepositoryUpdateProcessor.java @@ -1,5 +1,7 @@ package sonia.scm.repository.xml; +import sonia.scm.repository.RepositoryLocationResolver; + import javax.inject.Inject; import java.nio.file.Path; import java.util.function.BiConsumer; @@ -7,9 +9,9 @@ import java.util.function.BiConsumer; public class SingleRepositoryUpdateProcessor { @Inject - private PathBasedRepositoryLocationResolver locationResolver; + private RepositoryLocationResolver locationResolver; public void doUpdate(BiConsumer forEachRepository) { - locationResolver.forAllPaths(forEachRepository); + locationResolver.forClass(Path.class).forAllLocations(forEachRepository); } } 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 151e8f1281..1242c99641 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 @@ -40,7 +40,7 @@ import sonia.scm.repository.InternalRepositoryException; import sonia.scm.repository.NamespaceAndName; import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryDAO; -import sonia.scm.store.StoreConstants; +import sonia.scm.repository.RepositoryLocationResolver; import javax.inject.Inject; import java.io.IOException; @@ -76,18 +76,14 @@ public class XmlRepositoryDAO implements RepositoryDAO { } private void init() { - repositoryLocationResolver.forAllPaths((repositoryId, repositoryPath) -> { - Path metadataPath = resolveDataPath(repositoryPath); - Repository repository = metadataStore.read(metadataPath); + RepositoryLocationResolver.RepositoryLocationResolverInstance pathRepositoryLocationResolverInstance = repositoryLocationResolver.create(Path.class); + pathRepositoryLocationResolverInstance.forAllLocations((repositoryId, repositoryPath) -> { + Repository repository = metadataStore.read(repositoryPath); byNamespaceAndName.put(repository.getNamespaceAndName(), repository); byId.put(repositoryId, repository); }); } - private Path resolveDataPath(Path repositoryPath) { - return repositoryPath.resolve(StoreConstants.REPOSITORY_METADATA.concat(StoreConstants.FILE_EXTENSION)); - } - @Override public String getType() { return "xml"; @@ -108,8 +104,7 @@ public class XmlRepositoryDAO implements RepositoryDAO { Path repositoryPath = (Path) location; try { - Path metadataPath = resolveDataPath(repositoryPath); - metadataStore.write(metadataPath, repository); + metadataStore.write(repositoryPath, repository); } catch (Exception e) { repositoryLocationResolver.remove(repository.getId()); throw new InternalRepositoryException(repository, "failed to create filesystem", e); @@ -166,9 +161,8 @@ public class XmlRepositoryDAO implements RepositoryDAO { Path repositoryPath = repositoryLocationResolver .create(Path.class) .getLocation(repository.getId()); - Path metadataPath = resolveDataPath(repositoryPath); repositoryLocationResolver.updateModificationDate(); - metadataStore.write(metadataPath, clone); + metadataStore.write(repositoryPath, clone); } @Override diff --git a/scm-dao-xml/src/test/java/sonia/scm/repository/xml/PathBasedRepositoryLocationResolverTest.java b/scm-dao-xml/src/test/java/sonia/scm/repository/xml/PathBasedRepositoryLocationResolverTest.java index 941775d6ea..1c5a337abc 100644 --- a/scm-dao-xml/src/test/java/sonia/scm/repository/xml/PathBasedRepositoryLocationResolverTest.java +++ b/scm-dao-xml/src/test/java/sonia/scm/repository/xml/PathBasedRepositoryLocationResolverTest.java @@ -120,7 +120,7 @@ class PathBasedRepositoryLocationResolverTest { @Test void shouldInitWithExistingData() { Map foundRepositories = new HashMap<>(); - resolverWithExistingData.forAllPaths( + resolverWithExistingData.forClass(Path.class).forAllLocations( foundRepositories::put ); assertThat(foundRepositories) diff --git a/scm-dao-xml/src/test/java/sonia/scm/repository/xml/XmlRepositoryDAOTest.java b/scm-dao-xml/src/test/java/sonia/scm/repository/xml/XmlRepositoryDAOTest.java index bdf28310e1..f5571441e7 100644 --- a/scm-dao-xml/src/test/java/sonia/scm/repository/xml/XmlRepositoryDAOTest.java +++ b/scm-dao-xml/src/test/java/sonia/scm/repository/xml/XmlRepositoryDAOTest.java @@ -26,15 +26,13 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.Collection; import java.util.function.BiConsumer; +import java.util.function.Consumer; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.fail; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -47,6 +45,7 @@ class XmlRepositoryDAOTest { @Mock private PathBasedRepositoryLocationResolver locationResolver; + private Consumer> triggeredOnForAllLocations = none -> {}; private FileSystem fileSystem = new DefaultFileSystem(); @@ -69,6 +68,11 @@ class XmlRepositoryDAOTest { @Override public void setLocation(String repositoryId, Path location) { } + + @Override + public void forAllLocations(BiConsumer consumer) { + triggeredOnForAllLocations.accept(consumer); + } } ); when(locationResolver.create(anyString())).thenAnswer(invocation -> createMockedRepoPath(basePath, invocation)); @@ -332,11 +336,10 @@ class XmlRepositoryDAOTest { @Test void shouldRefreshWithExistingRepositoriesFromPathDatabase() { // given - doNothing().when(locationResolver).forAllPaths(any()); - XmlRepositoryDAO dao = new XmlRepositoryDAO(locationResolver, fileSystem); - mockExistingPath(); + XmlRepositoryDAO dao = new XmlRepositoryDAO(locationResolver, fileSystem); + // when dao.refresh(); @@ -346,12 +349,7 @@ class XmlRepositoryDAOTest { } private void mockExistingPath() { - doAnswer( - invocation -> { - ((BiConsumer) invocation.getArgument(0)).accept("existing", repositoryPath); - return null; - } - ).when(locationResolver).forAllPaths(any()); + triggeredOnForAllLocations = consumer -> consumer.accept("existing", repositoryPath); } } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitConfigHelper.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitConfigHelper.java new file mode 100644 index 0000000000..a978295166 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitConfigHelper.java @@ -0,0 +1,21 @@ +package sonia.scm.repository; + +import org.eclipse.jgit.lib.StoredConfig; + +import java.io.IOException; + +public class GitConfigHelper { + + private static final String CONFIG_SECTION_SCMM = "scmm"; + private static final String CONFIG_KEY_REPOSITORY_ID = "repositoryid"; + + public void createScmmConfig(Repository repository, org.eclipse.jgit.lib.Repository gitRepository) throws IOException { + StoredConfig config = gitRepository.getConfig(); + config.setString(CONFIG_SECTION_SCMM, null, CONFIG_KEY_REPOSITORY_ID, repository.getId()); + config.save(); + } + + public String getRepositoryId(StoredConfig gitConfig) { + return gitConfig.getString(CONFIG_SECTION_SCMM, null, CONFIG_KEY_REPOSITORY_ID); + } +} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryHandler.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryHandler.java index 63800e8a02..e07b3d0d83 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryHandler.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryHandler.java @@ -89,8 +89,6 @@ public class GitRepositoryHandler GitRepositoryServiceProvider.COMMANDS); private static final Object LOCK = new Object(); - private static final String CONFIG_SECTION_SCMM = "scmm"; - private static final String CONFIG_KEY_REPOSITORY_ID = "repositoryid"; private final Scheduler scheduler; @@ -185,7 +183,7 @@ public class GitRepositoryHandler } public String getRepositoryId(StoredConfig gitConfig) { - return gitConfig.getString(GitRepositoryHandler.CONFIG_SECTION_SCMM, null, GitRepositoryHandler.CONFIG_KEY_REPOSITORY_ID); + return new GitConfigHelper().getRepositoryId(gitConfig); } //~--- methods -------------------------------------------------------------- @@ -194,9 +192,7 @@ public class GitRepositoryHandler protected void create(Repository repository, File directory) throws IOException { try (org.eclipse.jgit.lib.Repository gitRepository = build(directory)) { gitRepository.create(true); - StoredConfig config = gitRepository.getConfig(); - config.setString(CONFIG_SECTION_SCMM, null, CONFIG_KEY_REPOSITORY_ID, repository.getId()); - config.save(); + new GitConfigHelper().createScmmConfig(repository, gitRepository); } } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/update/GitV1UpdateStep.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/update/GitV1UpdateStep.java new file mode 100644 index 0000000000..7cab0765a7 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/update/GitV1UpdateStep.java @@ -0,0 +1,70 @@ +package sonia.scm.repository.update; + +import org.eclipse.jgit.storage.file.FileRepositoryBuilder; +import sonia.scm.migration.UpdateException; +import sonia.scm.migration.UpdateStep; +import sonia.scm.plugin.Extension; +import sonia.scm.repository.GitConfigHelper; +import sonia.scm.repository.GitRepositoryHandler; +import sonia.scm.repository.Repository; +import sonia.scm.repository.RepositoryLocationResolver; +import sonia.scm.update.UpdateStepRepositoryMetadataAccess; +import sonia.scm.version.Version; + +import javax.inject.Inject; +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; + +import static sonia.scm.version.Version.parse; + +@Extension +public class GitV1UpdateStep implements UpdateStep { + + private final RepositoryLocationResolver locationResolver; + private final UpdateStepRepositoryMetadataAccess repositoryMetadataAccess; + + @Inject + public GitV1UpdateStep(RepositoryLocationResolver locationResolver, UpdateStepRepositoryMetadataAccess repositoryMetadataAccess) { + this.locationResolver = locationResolver; + this.repositoryMetadataAccess = repositoryMetadataAccess; + } + + @Override + public void doUpdate() { + locationResolver.forClass(Path.class).forAllLocations( + (repositoryId, path) -> { + Repository repository = repositoryMetadataAccess.read(path); + if (isGitDirectory(repository)) { + try (org.eclipse.jgit.lib.Repository gitRepository = build(path.resolve("data").toFile())) { + new GitConfigHelper().createScmmConfig(repository, gitRepository); + } catch (IOException e) { + throw new UpdateException("could not update repository with id " + repositoryId + " in path " + path, e); + } + } + } + ); + } + + private org.eclipse.jgit.lib.Repository build(File directory) throws IOException { + return new FileRepositoryBuilder() + .setGitDir(directory) + .readEnvironment() + .findGitDir() + .build(); + } + + private boolean isGitDirectory(Repository repository) { + return GitRepositoryHandler.TYPE_NAME.equals(repository.getType()); + } + + @Override + public Version getTargetVersion() { + return parse("2.0.0"); + } + + @Override + public String getAffectedDataType() { + return "sonia.scm.plugin.git"; + } +} diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgRepositoryHandler.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgRepositoryHandler.java index 4ccf13e738..0a8dfe065a 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgRepositoryHandler.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgRepositoryHandler.java @@ -41,13 +41,11 @@ import com.google.inject.Singleton; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sonia.scm.ConfigurationException; -import sonia.scm.ContextEntry; import sonia.scm.SCMContextProvider; import sonia.scm.installer.HgInstaller; import sonia.scm.installer.HgInstallerFactory; import sonia.scm.io.ExtendedCommand; import sonia.scm.io.INIConfiguration; -import sonia.scm.io.INIConfigurationReader; import sonia.scm.io.INIConfigurationWriter; import sonia.scm.io.INISection; import sonia.scm.plugin.Extension; @@ -347,14 +345,6 @@ public class HgRepositoryHandler writer.write(hgrc, hgrcFile); } - public String getRepositoryId(File directory) { - try { - return new INIConfigurationReader().read(new File(directory, PATH_HGRC)).getSection(CONFIG_SECTION_SCMM).getParameter(CONFIG_KEY_REPOSITORY_ID); - } catch (IOException e) { - throw new InternalRepositoryException(ContextEntry.ContextBuilder.entity("Directory", directory.toString()), "could not read scm configuration file", e); - } - } - //~--- get methods ---------------------------------------------------------- /** diff --git a/scm-test/src/main/java/sonia/scm/TempDirRepositoryLocationResolver.java b/scm-test/src/main/java/sonia/scm/TempDirRepositoryLocationResolver.java index acffe6c769..e172b53ba2 100644 --- a/scm-test/src/main/java/sonia/scm/TempDirRepositoryLocationResolver.java +++ b/scm-test/src/main/java/sonia/scm/TempDirRepositoryLocationResolver.java @@ -4,6 +4,7 @@ import sonia.scm.repository.BasicRepositoryLocationResolver; import java.io.File; import java.nio.file.Path; +import java.util.function.BiConsumer; public class TempDirRepositoryLocationResolver extends BasicRepositoryLocationResolver { private final File tempDirectory; @@ -30,6 +31,11 @@ public class TempDirRepositoryLocationResolver extends BasicRepositoryLocationRe public void setLocation(String repositoryId, T location) { throw new UnsupportedOperationException("not implemented for tests"); } + + @Override + public void forAllLocations(BiConsumer consumer) { + consumer.accept("id", (T) tempDirectory.toPath()); + } }; } } diff --git a/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/BootstrapModule.java b/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/BootstrapModule.java index 9b6ea719d8..fc8101d7cb 100644 --- a/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/BootstrapModule.java +++ b/scm-webapp/src/main/java/sonia/scm/lifecycle/modules/BootstrapModule.java @@ -10,6 +10,7 @@ import sonia.scm.io.DefaultFileSystem; import sonia.scm.io.FileSystem; import sonia.scm.plugin.PluginLoader; import sonia.scm.repository.RepositoryLocationResolver; +import sonia.scm.repository.xml.MetadataStore; import sonia.scm.repository.xml.PathBasedRepositoryLocationResolver; import sonia.scm.security.CipherHandler; import sonia.scm.security.CipherUtil; @@ -25,6 +26,7 @@ import sonia.scm.store.JAXBConfigurationStoreFactory; import sonia.scm.store.JAXBDataStoreFactory; import sonia.scm.store.JAXBPropertyFileAccess; import sonia.scm.update.PropertyFileAccess; +import sonia.scm.update.UpdateStepRepositoryMetadataAccess; import sonia.scm.update.V1PropertyDAO; import sonia.scm.update.xml.XmlV1PropertyDAO; @@ -65,6 +67,7 @@ public class BootstrapModule extends AbstractModule { bind(PluginLoader.class).toInstance(pluginLoader); bind(V1PropertyDAO.class, XmlV1PropertyDAO.class); bind(PropertyFileAccess.class, JAXBPropertyFileAccess.class); + bind(UpdateStepRepositoryMetadataAccess.class).to(MetadataStore.class); } private void bind(Class clazz, Class defaultImplementation) {