mirror of
https://github.com/scm-manager/scm-manager.git
synced 2026-05-06 20:45:26 +02:00
#910 fix missing instance id for newly created subversion repositories in format 7
This commit is contained in:
@@ -40,7 +40,8 @@ package sonia.scm.repository;
|
||||
public enum Compatibility
|
||||
{
|
||||
NONE(false, false, false, false, false),
|
||||
PRE14(true, true, true, true, false), PRE15(false, true, true, true, false),
|
||||
PRE14(true, true, true, true, false),
|
||||
PRE15(false, true, true, true, false),
|
||||
PRE16(false, false, true, true, false),
|
||||
PRE17(false, false, false, true, false),
|
||||
WITH17(false, false, false, false, true);
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
/**
|
||||
* 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. 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. 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.
|
||||
*
|
||||
* 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 DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON 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
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
package sonia.scm.repository;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.io.Files;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Fixes Subversion repositories with db format 7, but without an instance id in the db/uuid file.
|
||||
*
|
||||
* @see <a href="https://goo.gl/c3Ih89">910</a>
|
||||
* @author Sebastian Sdorra
|
||||
* @since 1.52
|
||||
*/
|
||||
public final class InstanceIDFix {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(InstanceIDFix.class);
|
||||
|
||||
private static final String PATH_DB = "db";
|
||||
private static final String PATH_FORMAT = "format";
|
||||
private static final String PATH_UUID = "uuid";
|
||||
|
||||
private static final String DB_FORMAT = "7";
|
||||
private static final Charset CHARSET = Charsets.US_ASCII;
|
||||
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
|
||||
|
||||
private final File repository;
|
||||
private final String dbFormat;
|
||||
private final List<String> uuids;
|
||||
|
||||
/**
|
||||
* Creates a new instance to fix subversion repositories.
|
||||
*
|
||||
* @param repository root directory of subversion repository
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public InstanceIDFix(File repository) throws IOException {
|
||||
this.repository = repository;
|
||||
this.dbFormat = readDBFormat(repository);
|
||||
this.uuids = readUUIDS(repository);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@core true} if the repository format is 7 and the instance id is missing.
|
||||
*
|
||||
* @return {@core true} if the repository must be fixed.
|
||||
*/
|
||||
public boolean isRequired() {
|
||||
return DB_FORMAT.equals(dbFormat) && uuids.size() == 1;
|
||||
}
|
||||
|
||||
private String readDBFormat(File directory) throws IOException {
|
||||
return Files.readFirstLine(dbFile(directory, PATH_FORMAT), CHARSET);
|
||||
}
|
||||
|
||||
private File dbFile(File directory, String filename) {
|
||||
return new File(directory, PATH_DB + File.separator + filename);
|
||||
}
|
||||
|
||||
private List<String> readUUIDS(File directory) throws IOException {
|
||||
return new ArrayList<>(Files.readLines(dbFile(directory, PATH_UUID), CHARSET));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add missing instance id to the uuid file of the repository and returns the generated instance id.
|
||||
*
|
||||
* @throws IOException
|
||||
* @return generated instance id
|
||||
*/
|
||||
public String addInstanceID() throws IOException {
|
||||
Preconditions.checkState(isRequired(), "repository has already an instance id and does not require the fix");
|
||||
String uuid = uuids.get(0);
|
||||
String instanceID = generateInstanceID();
|
||||
addInstanceID(uuid, instanceID);
|
||||
return instanceID;
|
||||
}
|
||||
|
||||
private void addInstanceID(String uuid, String instanceID) throws IOException {
|
||||
LOG.info("created instance id {} for subversion repository {} format 7", instanceID, uuid);
|
||||
String uuidFileContent = createUUIDFileContent(uuid, instanceID);
|
||||
Files.write(uuidFileContent, dbFile(repository, PATH_UUID), CHARSET);
|
||||
uuids.add(instanceID);
|
||||
}
|
||||
|
||||
private String generateInstanceID() {
|
||||
return UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
private String createUUIDFileContent(String uuid, String instanceID) {
|
||||
return new StringBuilder(uuid)
|
||||
.append(LINE_SEPARATOR)
|
||||
.append(instanceID)
|
||||
.append(LINE_SEPARATOR)
|
||||
.toString();
|
||||
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
List<String> getUuids() {
|
||||
return ImmutableList.copyOf(uuids);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
File getRepository() {
|
||||
return repository;
|
||||
}
|
||||
}
|
||||
@@ -317,6 +317,8 @@ public class SvnRepositoryHandler
|
||||
comp.isPre15Compatible(), comp.isPre16Compatible(),
|
||||
comp.isPre17Compatible(), comp.isWith17Compatible());
|
||||
|
||||
fixMissingInstanceID(directory);
|
||||
|
||||
svnRepository = SVNRepositoryFactory.create(url);
|
||||
|
||||
String uuid = svnRepository.getRepositoryUUID(true);
|
||||
@@ -346,6 +348,14 @@ public class SvnRepositoryHandler
|
||||
SvnUtil.closeSession(svnRepository);
|
||||
}
|
||||
}
|
||||
|
||||
private void fixMissingInstanceID(File directory) throws IOException {
|
||||
InstanceIDFix fix = new InstanceIDFix(directory);
|
||||
if (fix.isRequired()) {
|
||||
fix.addInstanceID();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Method description
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* 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.
|
||||
* 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.
|
||||
* 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.
|
||||
*
|
||||
* 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
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
package sonia.scm.repository;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.Rule;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.tmatesoft.svn.core.SVNException;
|
||||
import org.tmatesoft.svn.core.io.SVNRepositoryFactory;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link InstanceIDFix}.
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class InstanceIDFixTest {
|
||||
|
||||
@Rule
|
||||
public TemporaryFolder tempFolder = new TemporaryFolder();
|
||||
|
||||
@Test
|
||||
public void testIsRequired() throws SVNException, IOException {
|
||||
// svnkit uses db format 4 as default, so NONE must not be fixed
|
||||
assertFalse(createFix(Compatibility.NONE).isRequired());
|
||||
|
||||
assertFalse(createFix(Compatibility.PRE14).isRequired());
|
||||
assertFalse(createFix(Compatibility.PRE15).isRequired());
|
||||
assertFalse(createFix(Compatibility.PRE16).isRequired());
|
||||
|
||||
// WITH17 creates db format 7, which is subversion >= 1.9 or not?
|
||||
assertTrue(createFix(Compatibility.WITH17).isRequired());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddInstanceID() throws SVNException, IOException {
|
||||
InstanceIDFix fix = createFix(Compatibility.WITH17);
|
||||
assertTrue(fix.isRequired());
|
||||
|
||||
String instanceID = fix.addInstanceID();
|
||||
assertFalse(fix.isRequired());
|
||||
|
||||
fix = new InstanceIDFix(fix.getRepository());
|
||||
assertFalse(fix.isRequired());
|
||||
assertTrue(fix.getUuids().contains(instanceID));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void testAddInstanceIDAllreadyFixedRepository() throws SVNException, IOException {
|
||||
InstanceIDFix fix = createFix(Compatibility.WITH17);
|
||||
assertTrue(fix.isRequired());
|
||||
|
||||
fix.addInstanceID();
|
||||
fix.addInstanceID();
|
||||
}
|
||||
|
||||
private InstanceIDFix createFix(Compatibility compatibility) throws SVNException, IOException {
|
||||
return new InstanceIDFix(createRepository(compatibility));
|
||||
}
|
||||
|
||||
private File createRepository(Compatibility compatibility) throws SVNException, IOException {
|
||||
File directory = tempFolder.newFolder();
|
||||
SVNRepositoryFactory.createLocalRepository(directory, null, true, false, compatibility.isPre14Compatible(),
|
||||
compatibility.isPre15Compatible(), compatibility.isPre16Compatible(),
|
||||
compatibility.isPre17Compatible(), compatibility.isWith17Compatible());
|
||||
return directory;
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,8 @@ package sonia.scm.repository;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.io.Files;
|
||||
import sonia.scm.io.DefaultFileSystem;
|
||||
import sonia.scm.store.StoreFactory;
|
||||
|
||||
@@ -43,6 +45,9 @@ import static org.junit.Assert.*;
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -66,7 +71,7 @@ public class SvnRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase
|
||||
assertTrue(format.isFile());
|
||||
|
||||
File db = new File(directory, "db");
|
||||
|
||||
|
||||
assertTrue(db.exists());
|
||||
assertTrue(db.isDirectory());
|
||||
}
|
||||
@@ -96,4 +101,18 @@ public class SvnRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase
|
||||
|
||||
return handler;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreatedUUID() throws RepositoryException, IOException {
|
||||
SvnRepositoryHandler handler = (SvnRepositoryHandler) getHandler();
|
||||
handler.getConfig().setCompatibility(Compatibility.WITH17);
|
||||
|
||||
Repository repository = RepositoryTestData.createRestaurantAtTheEndOfTheUniverse();
|
||||
handler.create(repository);
|
||||
|
||||
File directory = handler.getDirectory(repository);
|
||||
File uuidFile = new File(directory, "db" + File.separator + "uuid");
|
||||
List<String> lines = Files.readLines(uuidFile, Charsets.UTF_8);
|
||||
assertEquals(2, lines.size());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,6 +76,11 @@ public abstract class SimpleRepositoryHandlerTestBase extends AbstractTestBase
|
||||
protected abstract RepositoryHandler createRepositoryHandler(
|
||||
StoreFactory factory, File directory);
|
||||
|
||||
|
||||
protected RepositoryHandler getHandler() {
|
||||
return handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
@@ -202,7 +207,7 @@ public abstract class SimpleRepositoryHandlerTestBase extends AbstractTestBase
|
||||
|
||||
/** Field description */
|
||||
protected File baseDirectory;
|
||||
|
||||
|
||||
/** Field description */
|
||||
private RepositoryHandler handler;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user