Use repository dao to find repository for given directory in hooks

This commit is contained in:
René Pfeuffer
2018-11-23 10:13:47 +01:00
parent 4925370a43
commit e8558e07ec
13 changed files with 79 additions and 253 deletions

View File

@@ -36,6 +36,8 @@ package sonia.scm.repository;
import sonia.scm.GenericDAO;
import java.io.File;
/**
* Data access object for repositories. This class should only used by the
* {@link RepositoryManager}. Plugins and other classes should use the
@@ -67,4 +69,13 @@ public interface RepositoryDAO extends GenericDAO<Repository>
* @return repository with the specified namespace and name or null
*/
Repository get(NamespaceAndName namespaceAndName);
/**
* Returns the repository that is associated with the given path. This path
* may be the root directory of the repository or any other directory or file
* inside the root directory.
*
* @throws {@link RuntimeException} when there is no repository for the given path.
*/
String getIdForDirectory(File path);
}

View File

@@ -21,7 +21,7 @@ import java.io.File;
@Singleton
public class RepositoryLocationResolver {
private static final String REPOSITORIES_NATIVE_DIRECTORY = "data";
static final String REPOSITORIES_NATIVE_DIRECTORY = "data";
private RepositoryDAO repositoryDAO;
private InitialRepositoryLocationResolver initialRepositoryLocationResolver;

View File

@@ -1,119 +0,0 @@
/**
* 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;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Preconditions;
import sonia.scm.io.DirectoryFileFilter;
import sonia.scm.util.IOUtil;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
//~--- JDK imports ------------------------------------------------------------
/**
*
* @author Sebastian Sdorra
* @since 1.11
*/
public final class RepositoryUtil {
private RepositoryUtil() {}
public static List<File> searchRepositoryDirectories(File directory, String... names) {
List<File> repositories = new ArrayList<>();
searchRepositoryDirectories(repositories, directory, Arrays.asList(names));
return repositories;
}
@SuppressWarnings("squid:S2083") // ignore, because the path is validated at {@link #getRepositoryId(File, File)}
public static String getRepositoryId(RepositoryDirectoryHandler handler, String directoryPath) throws IOException {
return getRepositoryId(handler.getInitialBaseDirectory(), new File(directoryPath));
}
public static String getRepositoryId(RepositoryDirectoryHandler handler, File directory) throws IOException {
return getRepositoryId(handler.getInitialBaseDirectory(), directory);
}
public static String getRepositoryId(File baseDirectory, File directory) throws IOException {
String path = directory.getCanonicalPath();
String basePath = baseDirectory.getCanonicalPath();
Preconditions.checkArgument(
path.startsWith(basePath),
"repository path %s is not in the main repository path %s", path, basePath
);
String id = IOUtil.trimSeperatorChars(path.substring(basePath.length()).replace(RepositoryLocationResolver.REPOSITORIES_NATIVE_DIRECTORY, ""));
Preconditions.checkArgument(
!id.contains("\\") && !id.contains("/"),
"got illegal repository directory with separators in id: %s", path
);
return id;
}
private static void searchRepositoryDirectories(List<File> repositories, File directory, List<String> names) {
boolean found = false;
for (String name : names) {
if (new File(directory, name).exists()) {
found = true;
break;
}
}
if (found) {
repositories.add(directory);
} else {
File[] directories = directory.listFiles(DirectoryFileFilter.instance);
if (directories != null) {
for (File d : directories) {
searchRepositoryDirectories(repositories, d, names);
}
}
}
}
}

View File

@@ -44,7 +44,9 @@ import sonia.scm.repository.Repository;
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;
@@ -154,9 +156,18 @@ public class XmlRepositoryDAO
.resolve(findExistingRepositoryPath(repository).map(RepositoryPath::getPath).orElse(initialRepositoryLocationResolver.getRelativeRepositoryPath(repository)));
}
@Override
public String getIdForDirectory(File path) {
return db.getPaths().stream()
.filter(p -> path.toPath().startsWith(context.getBaseDirectory().toPath().resolve(p.getPath()).toAbsolutePath()))
.map(RepositoryPath::getId)
.findAny()
.orElseThrow(() -> new RuntimeException("could not find repository for directory: " + path));
}
private Optional<RepositoryPath> findExistingRepositoryPath(Repository repository) {
return db.getPaths().stream()
.filter(repoPath -> repoPath.getId().equals(repository.getId()))
.findFirst();
.findAny();
}
}

View File

@@ -38,24 +38,21 @@ package org.eclipse.jgit.transport;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Inject;
import com.google.inject.Provider;
import org.eclipse.jgit.errors.NoRemoteRepositoryException;
import org.eclipse.jgit.errors.NotSupportedException;
import org.eclipse.jgit.errors.TransportException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryCache;
import sonia.scm.repository.GitRepositoryHandler;
import sonia.scm.repository.RepositoryDAO;
import sonia.scm.repository.spi.HookEventFacade;
import sonia.scm.web.GitReceiveHook;
//~--- JDK imports ------------------------------------------------------------
import java.io.File;
import java.util.Set;
//~--- JDK imports ------------------------------------------------------------
/**
*
* @author Sebastian Sdorra
@@ -75,24 +72,15 @@ public class ScmTransportProtocol extends TransportProtocol
* Constructs ...
*
*/
public ScmTransportProtocol() {}
// public ScmTransportProtocol() {}
/**
* Constructs ...
*
*
*
* @param hookEventFacadeProvider
*
* @param repositoryHandlerProvider
*/
@Inject
public ScmTransportProtocol(
Provider<HookEventFacade> hookEventFacadeProvider,
Provider<GitRepositoryHandler> repositoryHandlerProvider)
RepositoryDAO repositoryDAO)
{
this.hookEventFacadeProvider = hookEventFacadeProvider;
this.repositoryHandlerProvider = repositoryHandlerProvider;
this.repositoryDAO = repositoryDAO;
}
//~--- methods --------------------------------------------------------------
@@ -136,7 +124,7 @@ public class ScmTransportProtocol extends TransportProtocol
*/
@Override
public Transport open(URIish uri, Repository local, String remoteName)
throws NotSupportedException, TransportException
throws TransportException
{
File localDirectory = local.getDirectory();
File path = local.getFS().resolve(localDirectory, uri.getPath());
@@ -150,8 +138,7 @@ public class ScmTransportProtocol extends TransportProtocol
//J-
return new TransportLocalWithHooks(
hookEventFacadeProvider.get(),
repositoryHandlerProvider.get(),
local, uri, gitDir
local, uri, gitDir, repositoryDAO
);
//J+
}
@@ -194,23 +181,12 @@ public class ScmTransportProtocol extends TransportProtocol
private static class TransportLocalWithHooks extends TransportLocal
{
/**
* Constructs ...
*
*
*
* @param hookEventFacade
* @param handler
* @param local
* @param uri
* @param gitDir
*/
public TransportLocalWithHooks(HookEventFacade hookEventFacade,
GitRepositoryHandler handler, Repository local, URIish uri, File gitDir)
Repository local, URIish uri, File gitDir, RepositoryDAO repositoryDAO)
{
super(local, uri, gitDir);
this.hookEventFacade = hookEventFacade;
this.handler = handler;
this.repositoryDAO = repositoryDAO;
}
//~--- methods ------------------------------------------------------------
@@ -228,9 +204,9 @@ public class ScmTransportProtocol extends TransportProtocol
{
ReceivePack pack = new ReceivePack(dst);
if ((hookEventFacade != null) && (handler != null))
if (hookEventFacade != null)
{
GitReceiveHook hook = new GitReceiveHook(hookEventFacade, handler);
GitReceiveHook hook = new GitReceiveHook(hookEventFacade, repositoryDAO);
pack.setPreReceiveHook(hook);
pack.setPostReceiveHook(hook);
@@ -241,11 +217,9 @@ public class ScmTransportProtocol extends TransportProtocol
//~--- fields -------------------------------------------------------------
/** Field description */
private GitRepositoryHandler handler;
/** Field description */
private HookEventFacade hookEventFacade;
private RepositoryDAO repositoryDAO;
}
@@ -254,6 +228,5 @@ public class ScmTransportProtocol extends TransportProtocol
/** Field description */
private Provider<HookEventFacade> hookEventFacadeProvider;
/** Field description */
private Provider<GitRepositoryHandler> repositoryHandlerProvider;
private RepositoryDAO repositoryDAO;
}

View File

@@ -42,9 +42,8 @@ import org.eclipse.jgit.transport.ReceiveCommand;
import org.eclipse.jgit.transport.ReceivePack;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.repository.GitRepositoryHandler;
import sonia.scm.repository.RepositoryDAO;
import sonia.scm.repository.RepositoryHookType;
import sonia.scm.repository.RepositoryUtil;
import sonia.scm.repository.spi.GitHookContextProvider;
import sonia.scm.repository.spi.HookEventFacade;
@@ -68,19 +67,10 @@ public class GitReceiveHook implements PreReceiveHook, PostReceiveHook
//~--- constructors ---------------------------------------------------------
/**
* Constructs ...
*
*
*
* @param hookEventFacade
* @param handler
*/
public GitReceiveHook(HookEventFacade hookEventFacade,
GitRepositoryHandler handler)
public GitReceiveHook(HookEventFacade hookEventFacade, RepositoryDAO repositoryDAO)
{
this.hookEventFacade = hookEventFacade;
this.handler = handler;
this.repositoryDAO = repositoryDAO;
}
//~--- methods --------------------------------------------------------------
@@ -187,7 +177,7 @@ public class GitReceiveHook implements PreReceiveHook, PostReceiveHook
*
* @throws IOException
*/
private String resolveRepositoryId(Repository repository) throws IOException
private String resolveRepositoryId(Repository repository)
{
File directory;
@@ -200,14 +190,13 @@ public class GitReceiveHook implements PreReceiveHook, PostReceiveHook
directory = repository.getWorkTree();
}
return RepositoryUtil.getRepositoryId(handler, directory);
return repositoryDAO.getIdForDirectory(directory);
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private GitRepositoryHandler handler;
/** Field description */
private HookEventFacade hookEventFacade;
private final RepositoryDAO repositoryDAO;
}

View File

@@ -36,21 +36,19 @@ package sonia.scm.web;
//~--- non-JDK imports --------------------------------------------------------
import com.google.inject.Inject;
import org.eclipse.jgit.http.server.resolver.DefaultReceivePackFactory;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.transport.ReceivePack;
import org.eclipse.jgit.transport.resolver.ReceivePackFactory;
import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
import sonia.scm.repository.GitRepositoryHandler;
import sonia.scm.repository.RepositoryDAO;
import sonia.scm.repository.spi.HookEventFacade;
//~--- JDK imports ------------------------------------------------------------
import javax.servlet.http.HttpServletRequest;
//~--- JDK imports ------------------------------------------------------------
/**
*
* @author Sebastian Sdorra
@@ -59,19 +57,10 @@ public class GitReceivePackFactory
implements ReceivePackFactory<HttpServletRequest>
{
/**
* Constructs ...
*
*
*
* @param hookEventFacade
* @param handler
*/
@Inject
public GitReceivePackFactory(HookEventFacade hookEventFacade,
GitRepositoryHandler handler)
public GitReceivePackFactory(HookEventFacade hookEventFacade, RepositoryDAO repositoryDAO)
{
hook = new GitReceiveHook(hookEventFacade, handler);
hook = new GitReceiveHook(hookEventFacade, repositoryDAO);
}
//~--- methods --------------------------------------------------------------

View File

@@ -127,15 +127,7 @@ public class AbstractRemoteCommandTestBase
{
return null;
}
}, new Provider<GitRepositoryHandler>()
{
@Override
public GitRepositoryHandler get()
{
return null;
}
});
}, null);
Transport.register(proto);
}

View File

@@ -48,8 +48,8 @@ import sonia.scm.NotFoundException;
import sonia.scm.repository.HgContext;
import sonia.scm.repository.HgHookManager;
import sonia.scm.repository.HgRepositoryHandler;
import sonia.scm.repository.RepositoryDAO;
import sonia.scm.repository.RepositoryHookType;
import sonia.scm.repository.RepositoryUtil;
import sonia.scm.repository.api.HgHookMessage;
import sonia.scm.repository.api.HgHookMessage.Severity;
import sonia.scm.repository.spi.HgHookContextProvider;
@@ -63,6 +63,7 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
@@ -113,25 +114,16 @@ public class HgHookCallbackServlet extends HttpServlet
//~--- constructors ---------------------------------------------------------
/**
* Constructs ...
*
*
*
* @param hookEventFacade
* @param handler
* @param hookManager
* @param contextProvider
*/
@Inject
public HgHookCallbackServlet(HookEventFacade hookEventFacade,
HgRepositoryHandler handler, HgHookManager hookManager,
Provider<HgContext> contextProvider)
Provider<HgContext> contextProvider, RepositoryDAO repositoryDAO)
{
this.hookEventFacade = hookEventFacade;
this.handler = handler;
this.hookManager = hookManager;
this.contextProvider = contextProvider;
this.repositoryDAO = repositoryDAO;
}
//~--- methods --------------------------------------------------------------
@@ -148,7 +140,6 @@ public class HgHookCallbackServlet extends HttpServlet
*/
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
String ping = request.getParameter(PARAM_PING);
@@ -463,21 +454,12 @@ public class HgHookCallbackServlet extends HttpServlet
String id = null;
String path = request.getParameter(PARAM_REPOSITORYPATH);
if (Util.isNotEmpty(path))
{
/**
if (Util.isNotEmpty(path)) {
/*
* use canonical path to fix symbolic links
* https://bitbucket.org/sdorra/scm-manager/issue/82/symbolic-link-in-hg-repository-path
*/
try
{
id = RepositoryUtil.getRepositoryId(handler, path);
}
catch (IOException ex)
{
logger.error("could not find namespace and name of repository", ex);
}
id = repositoryDAO.getIdForDirectory(new File(path));
}
else if (logger.isWarnEnabled())
{
@@ -500,4 +482,6 @@ public class HgHookCallbackServlet extends HttpServlet
/** Field description */
private final HgHookManager hookManager;
private final RepositoryDAO repositoryDAO;
}

View File

@@ -1,8 +1,8 @@
package sonia.scm.web;
import org.junit.Test;
import sonia.scm.repository.HgConfig;
import sonia.scm.repository.HgRepositoryHandler;
import sonia.scm.repository.RepositoryDAO;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
@@ -22,7 +22,9 @@ public class HgHookCallbackServletTest {
@Test
public void shouldExtractCorrectRepositoryId() throws ServletException, IOException {
HgRepositoryHandler handler = mock(HgRepositoryHandler.class);
HgHookCallbackServlet servlet = new HgHookCallbackServlet(null, handler, null, null);
RepositoryDAO repositoryDAO = mock(RepositoryDAO.class);
when(repositoryDAO.getIdForDirectory(new File("/tmp/hg/12345"))).thenReturn("12345");
HgHookCallbackServlet servlet = new HgHookCallbackServlet(null, handler, null, null, repositoryDAO);
HttpServletRequest request = mock(HttpServletRequest.class);
HttpServletResponse response = mock(HttpServletResponse.class);

View File

@@ -90,7 +90,8 @@ public class SvnRepositoryHandler
FileSystem fileSystem,
HookEventFacade eventFacade,
RepositoryLocationResolver repositoryLocationResolver,
InitialRepositoryLocationResolver initialRepositoryLocationResolver)
InitialRepositoryLocationResolver initialRepositoryLocationResolver,
RepositoryDAO repositoryDAO)
{
super(storeFactory, fileSystem, repositoryLocationResolver, initialRepositoryLocationResolver);
@@ -103,7 +104,7 @@ public class SvnRepositoryHandler
// register hook
if (eventFacade != null)
{
FSHooks.registerHook(new SvnRepositoryHook(eventFacade, this));
FSHooks.registerHook(new SvnRepositoryHook(eventFacade, repositoryDAO));
}
else if (logger.isWarnEnabled())
{

View File

@@ -70,19 +70,10 @@ public class SvnRepositoryHook implements FSHook
//~--- constructors ---------------------------------------------------------
/**
* Constructs ...
*
*
*
* @param hookEventFacade
* @param handler
*/
public SvnRepositoryHook(HookEventFacade hookEventFacade,
SvnRepositoryHandler handler)
public SvnRepositoryHook(HookEventFacade hookEventFacade, RepositoryDAO repositoryDAO)
{
this.hookEventFacade = hookEventFacade;
this.handler = handler;
this.repositoryDAO = repositoryDAO;
}
//~--- methods --------------------------------------------------------------
@@ -197,18 +188,17 @@ public class SvnRepositoryHook implements FSHook
*
* @throws IOException
*/
private String getRepositoryId(File directory) throws IOException
private String getRepositoryId(File directory)
{
AssertUtil.assertIsNotNull(directory);
return RepositoryUtil.getRepositoryId(handler, directory);
return repositoryDAO.getIdForDirectory(directory);
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private SvnRepositoryHandler handler;
/** Field description */
private HookEventFacade hookEventFacade;
private final RepositoryDAO repositoryDAO;
}

View File

@@ -68,6 +68,9 @@ public class SvnRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase {
@Mock
private com.google.inject.Provider<RepositoryManager> repositoryManagerProvider;
@Mock
private RepositoryDAO repositoryDAO;
private HookContextFactory hookContextFactory = new HookContextFactory(mock(PreProcessorUtil.class));
private HookEventFacade facade = new HookEventFacade(repositoryManagerProvider, hookContextFactory);
@@ -93,7 +96,7 @@ public class SvnRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase {
File directory) {
initialRepositoryLocationResolver = new InitialRepositoryLocationResolver(contextProvider);
repositoryLocationResolver = new RepositoryLocationResolver(repoDao, initialRepositoryLocationResolver);
SvnRepositoryHandler handler = new SvnRepositoryHandler(factory, new DefaultFileSystem(), null, repositoryLocationResolver, initialRepositoryLocationResolver);
SvnRepositoryHandler handler = new SvnRepositoryHandler(factory, new DefaultFileSystem(), null, repositoryLocationResolver, initialRepositoryLocationResolver, repositoryDAO);
handler.init(contextProvider);
@@ -109,7 +112,7 @@ public class SvnRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase {
public void getDirectory() {
when(factory.getStore(any(), any())).thenReturn(store);
SvnRepositoryHandler repositoryHandler = new SvnRepositoryHandler(factory,
new DefaultFileSystem(), facade, repositoryLocationResolver, initialRepositoryLocationResolver);
new DefaultFileSystem(), facade, repositoryLocationResolver, initialRepositoryLocationResolver, repositoryDAO);
SvnConfig svnConfig = new SvnConfig();
repositoryHandler.setConfig(svnConfig);