diff --git a/scm-webapp/src/main/java/sonia/scm/repository/update/XmlRepositoryV1UpdateStep.java b/scm-webapp/src/main/java/sonia/scm/repository/update/XmlRepositoryV1UpdateStep.java
index d21eb079fa..c1ef200335 100644
--- a/scm-webapp/src/main/java/sonia/scm/repository/update/XmlRepositoryV1UpdateStep.java
+++ b/scm-webapp/src/main/java/sonia/scm/repository/update/XmlRepositoryV1UpdateStep.java
@@ -24,10 +24,30 @@ import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.stream.Collectors;
+import static java.util.Optional.empty;
+import static java.util.Optional.of;
import static sonia.scm.version.Version.parse;
+/**
+ * Migrates SCM-Manager v1 repository data structure to SCM-Manager v2 data structure.
+ * That is:
+ *
+ * - The old
repositories.xml file is read
+ * - For each repository in this database,
+ *
+ * - a new entry in the new
repository-paths.xml database is written,
+ * - the data directory is moved or copied to a SCM v2 consistent directory. How this is done
+ * can be specified by a strategy (@see {@link MigrationStrategy}), that has to be set in
+ * a database file named
migration-plan.xml (to create this file, use {@link MigrationStrategyDao}),
+ * and
+ * - the new
metadata.xml file is created.
+ *
+ *
+ *
+ */
@Extension
public class XmlRepositoryV1UpdateStep implements UpdateStep {
@@ -62,8 +82,9 @@ public class XmlRepositoryV1UpdateStep implements UpdateStep {
return;
}
JAXBContext jaxbContext = JAXBContext.newInstance(V1RepositoryDatabase.class);
- V1RepositoryDatabase v1Database = readV1Database(jaxbContext);
- v1Database.repositoryList.repositories.forEach(this::update);
+ readV1Database(jaxbContext).ifPresent(
+ v1Database -> v1Database.repositoryList.repositories.forEach(this::update)
+ );
}
private void update(V1Repository v1Repository) {
@@ -82,7 +103,7 @@ public class XmlRepositoryV1UpdateStep implements UpdateStep {
private Path handleDataDirectory(V1Repository v1Repository) {
MigrationStrategy dataMigrationStrategy =
migrationStrategyDao.get(v1Repository.id)
- .orElseThrow(() -> new IllegalStateException("no strategy found for repository with id " + v1Repository.id + " and name " + v1Repository.name));
+ .orElseThrow(() -> new IllegalStateException("no strategy found for repository with id " + v1Repository.id + " and name " + v1Repository.name));
return dataMigrationStrategy.from(injector).migrate(v1Repository.id, v1Repository.name, v1Repository.type);
}
@@ -102,12 +123,12 @@ public class XmlRepositoryV1UpdateStep implements UpdateStep {
private String getNamespace(V1Repository v1Repository) {
String[] nameParts = getNameParts(v1Repository.name);
- return nameParts.length > 1? nameParts[0]: v1Repository.type;
+ return nameParts.length > 1 ? nameParts[0] : v1Repository.type;
}
private String getName(V1Repository v1Repository) {
String[] nameParts = getNameParts(v1Repository.name);
- return nameParts.length == 1? nameParts[0]: concatPathElements(nameParts);
+ return nameParts.length == 1 ? nameParts[0] : concatPathElements(nameParts);
}
private String concatPathElements(String[] nameParts) {
@@ -118,8 +139,13 @@ public class XmlRepositoryV1UpdateStep implements UpdateStep {
return v1Name.split("/");
}
- private V1RepositoryDatabase readV1Database(JAXBContext jaxbContext) throws JAXBException {
- return (V1RepositoryDatabase) jaxbContext.createUnmarshaller().unmarshal(determineV1File());
+ private Optional readV1Database(JAXBContext jaxbContext) throws JAXBException {
+ Object unmarshal = jaxbContext.createUnmarshaller().unmarshal(determineV1File());
+ if (unmarshal instanceof V1RepositoryDatabase) {
+ return of((V1RepositoryDatabase) unmarshal);
+ } else {
+ return empty();
+ }
}
private File determineV1File() {
diff --git a/scm-webapp/src/test/java/sonia/scm/repository/update/XmlRepositoryV1UpdateStepTest.java b/scm-webapp/src/test/java/sonia/scm/repository/update/XmlRepositoryV1UpdateStepTest.java
index 9b455b9590..3b0008f3c6 100644
--- a/scm-webapp/src/test/java/sonia/scm/repository/update/XmlRepositoryV1UpdateStepTest.java
+++ b/scm-webapp/src/test/java/sonia/scm/repository/update/XmlRepositoryV1UpdateStepTest.java
@@ -1,5 +1,6 @@
package sonia.scm.repository.update;
+import com.google.common.io.Resources;
import com.google.inject.Injector;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
@@ -14,11 +15,12 @@ import org.mockito.junit.jupiter.MockitoExtension;
import sonia.scm.SCMContextProvider;
import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryPermission;
-import sonia.scm.repository.spi.ZippedRepositoryTestBase;
import sonia.scm.repository.xml.XmlRepositoryDAO;
import javax.xml.bind.JAXBException;
import java.io.IOException;
+import java.net.URL;
+import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Optional;
@@ -165,7 +167,15 @@ class XmlRepositoryV1UpdateStepTest {
@Test
void shouldNotFailIfNoOldDatabaseExists() throws JAXBException {
updateStep.doUpdate();
+ }
+ @Test
+ void shouldNotFailIfFormerV1DatabaseExists(@TempDirectory.TempDir Path tempDir) throws JAXBException, IOException {
+ URL url = Resources.getResource("sonia/scm/repository/update/formerV2RepositoryFile.xml");
+ Path configDir = tempDir.resolve("config");
+ Files.createDirectories(configDir);
+ Files.copy(url.openStream(), configDir.resolve("repositories.xml"));
+ updateStep.doUpdate();
}
private Optional findByNamespace(String namespace) {
diff --git a/scm-webapp/src/test/resources/sonia/scm/repository/update/formerV2RepositoryFile.xml b/scm-webapp/src/test/resources/sonia/scm/repository/update/formerV2RepositoryFile.xml
new file mode 100644
index 0000000000..ca21ead549
--- /dev/null
+++ b/scm-webapp/src/test/resources/sonia/scm/repository/update/formerV2RepositoryFile.xml
@@ -0,0 +1,4 @@
+
+
+ repositories/C2RRHjjeL2
+