mirror of
				https://github.com/scm-manager/scm-manager.git
				synced 2025-11-03 20:15:52 +01:00 
			
		
		
		
	remove all items from lfs blob store, if the corresponding repository was removed
This commit is contained in:
		@@ -40,6 +40,8 @@ import com.google.inject.servlet.ServletModule;
 | 
			
		||||
import org.eclipse.jgit.transport.ScmTransportProtocol;
 | 
			
		||||
 | 
			
		||||
import sonia.scm.plugin.ext.Extension;
 | 
			
		||||
import sonia.scm.web.lfs.LfsBlobStoreFactory;
 | 
			
		||||
import sonia.scm.web.lfs.LfsStoreRemoveListener;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *
 | 
			
		||||
@@ -68,6 +70,9 @@ public class GitServletModule extends ServletModule
 | 
			
		||||
    bind(GitRepositoryResolver.class);
 | 
			
		||||
    bind(GitReceivePackFactory.class);
 | 
			
		||||
    bind(ScmTransportProtocol.class);
 | 
			
		||||
    
 | 
			
		||||
    bind(LfsBlobStoreFactory.class);
 | 
			
		||||
    bind(LfsStoreRemoveListener.class);
 | 
			
		||||
 | 
			
		||||
    // serlvelts and filters
 | 
			
		||||
    filter(PATTERN_GIT).through(GitBasicAuthenticationFilter.class);
 | 
			
		||||
 
 | 
			
		||||
@@ -168,13 +168,13 @@ public class ScmGitServlet extends GitServlet
 | 
			
		||||
  private void handleRequest(HttpServletRequest request, HttpServletResponse response, Repository repository) throws ServletException, IOException {
 | 
			
		||||
    logger.trace("handle git repository at {}", repository.getName());
 | 
			
		||||
    if (isLfsBatchApiRequest(request, repository.getName())) {
 | 
			
		||||
      
 | 
			
		||||
      HttpServlet servlet = lfsServletFactory.createProtocolServletFor(repository, request);
 | 
			
		||||
      logger.trace("handle lfs batch api request");
 | 
			
		||||
      handleGitLfsRequest(request, response, repository);
 | 
			
		||||
      handleGitLfsRequest(servlet, request, response, repository);
 | 
			
		||||
    } else if (isLfsFileTransferRequest(request, repository.getName())) {
 | 
			
		||||
 | 
			
		||||
      HttpServlet servlet = lfsServletFactory.createFileLfsServletFor(repository, request);
 | 
			
		||||
      logger.trace("handle lfs file transfer request");
 | 
			
		||||
      handleGitLfsRequest(request, response, repository);
 | 
			
		||||
      handleGitLfsRequest(servlet, request, response, repository);
 | 
			
		||||
    } else if (isRegularGitAPIRequest(request)) {
 | 
			
		||||
      logger.trace("handle regular git request");
 | 
			
		||||
      // continue with the regular git Backend
 | 
			
		||||
@@ -189,8 +189,7 @@ public class ScmGitServlet extends GitServlet
 | 
			
		||||
    return REGEX_GITHTTPBACKEND.matcher(HttpUtil.getStrippedURI(request)).matches();
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  private void handleGitLfsRequest(HttpServletRequest request, HttpServletResponse response, Repository repository) throws ServletException, IOException {
 | 
			
		||||
    HttpServlet servlet = lfsServletFactory.createProtocolServletFor(repository, request);
 | 
			
		||||
  private void handleGitLfsRequest(HttpServlet servlet, HttpServletRequest request, HttpServletResponse response, Repository repository) throws ServletException, IOException {
 | 
			
		||||
    if (repositoryRequestListenerUtil.callListeners(request, response, repository)) {
 | 
			
		||||
      servlet.service(request, response);
 | 
			
		||||
    } else if (logger.isDebugEnabled()) {
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,80 @@
 | 
			
		||||
/**
 | 
			
		||||
 * 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.web.lfs;
 | 
			
		||||
 | 
			
		||||
import com.google.inject.Inject;
 | 
			
		||||
import com.google.inject.Singleton;
 | 
			
		||||
import sonia.scm.repository.Repository;
 | 
			
		||||
import sonia.scm.store.BlobStore;
 | 
			
		||||
import sonia.scm.store.BlobStoreFactory;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Creates {@link BlobStore} objects to store lfs objects.
 | 
			
		||||
 * 
 | 
			
		||||
 * @author Sebastian Sdorra
 | 
			
		||||
 * @since 1.54
 | 
			
		||||
 */
 | 
			
		||||
@Singleton
 | 
			
		||||
public class LfsBlobStoreFactory {
 | 
			
		||||
  
 | 
			
		||||
  private static final String GIT_LFS_REPOSITORY_POSTFIX = "-git-lfs";
 | 
			
		||||
  
 | 
			
		||||
  private final BlobStoreFactory blobStoreFactory;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Create a new instance.
 | 
			
		||||
   * 
 | 
			
		||||
   * @param blobStoreFactory blob store factory
 | 
			
		||||
   */
 | 
			
		||||
  @Inject
 | 
			
		||||
  public LfsBlobStoreFactory(BlobStoreFactory blobStoreFactory) {
 | 
			
		||||
    this.blobStoreFactory = blobStoreFactory;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  /**
 | 
			
		||||
   * Provides a {@link BlobStore} corresponding to the SCM Repository.
 | 
			
		||||
   * <p>
 | 
			
		||||
   * git-lfs repositories should generally carry the same name as their regular SCM repository counterparts. However,
 | 
			
		||||
   * we have decided to store them under their IDs instead of their names, since the names might change and provide
 | 
			
		||||
   * other drawbacks, as well.
 | 
			
		||||
   * <p>
 | 
			
		||||
   * These repositories will have {@linkplain #GIT_LFS_REPOSITORY_POSTFIX} appended to their IDs.
 | 
			
		||||
   *
 | 
			
		||||
   * @param repository The SCM Repository to provide a LFS {@link BlobStore} for.
 | 
			
		||||
   * 
 | 
			
		||||
   * @return blob store for the corresponding scm repository
 | 
			
		||||
   */
 | 
			
		||||
  public BlobStore getLfsBlobStore(Repository repository) {
 | 
			
		||||
    return blobStoreFactory.getBlobStore(repository.getId() + GIT_LFS_REPOSITORY_POSTFIX);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,97 @@
 | 
			
		||||
/**
 | 
			
		||||
 * 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.web.lfs;
 | 
			
		||||
 | 
			
		||||
import com.google.common.eventbus.Subscribe;
 | 
			
		||||
import com.google.inject.Inject;
 | 
			
		||||
import org.slf4j.Logger;
 | 
			
		||||
import org.slf4j.LoggerFactory;
 | 
			
		||||
import sonia.scm.EagerSingleton;
 | 
			
		||||
import sonia.scm.HandlerEvent;
 | 
			
		||||
import sonia.scm.plugin.ext.Extension;
 | 
			
		||||
import sonia.scm.repository.GitRepositoryHandler;
 | 
			
		||||
import sonia.scm.repository.Repository;
 | 
			
		||||
import sonia.scm.repository.RepositoryEvent;
 | 
			
		||||
import sonia.scm.store.Blob;
 | 
			
		||||
import sonia.scm.store.BlobStore;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Listener which removes all lfs objects from a blob store, whenever its corresponding git repository gets deleted.
 | 
			
		||||
 * 
 | 
			
		||||
 * @author Sebastian Sdorra
 | 
			
		||||
 * @since 1.54
 | 
			
		||||
 */
 | 
			
		||||
@Extension
 | 
			
		||||
@EagerSingleton
 | 
			
		||||
public class LfsStoreRemoveListener {
 | 
			
		||||
  
 | 
			
		||||
  private static final Logger LOG = LoggerFactory.getLogger(LfsBlobStoreFactory.class);
 | 
			
		||||
  
 | 
			
		||||
  private final LfsBlobStoreFactory lfsBlobStoreFactory;
 | 
			
		||||
 | 
			
		||||
  @Inject
 | 
			
		||||
  public LfsStoreRemoveListener(LfsBlobStoreFactory lfsBlobStoreFactory) {
 | 
			
		||||
    this.lfsBlobStoreFactory = lfsBlobStoreFactory;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  /**
 | 
			
		||||
   * Remove all object from the blob store, if the event is an delete event and the repository is a git repository.
 | 
			
		||||
   * 
 | 
			
		||||
   * @param event repository event
 | 
			
		||||
   */
 | 
			
		||||
  @Subscribe
 | 
			
		||||
  public void handleRepositoryEvent(RepositoryEvent event) {
 | 
			
		||||
    if ( isDeleteEvent(event) && isGitRepositoryEvent(event) ) {
 | 
			
		||||
      removeLfsStore(event.getItem());
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  private boolean isDeleteEvent(RepositoryEvent event) {
 | 
			
		||||
    return HandlerEvent.DELETE == event.getEventType();
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  private boolean isGitRepositoryEvent(RepositoryEvent event) {
 | 
			
		||||
    return event.getItem() != null 
 | 
			
		||||
        && event.getItem().getType().equals(GitRepositoryHandler.TYPE_NAME);
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  private void removeLfsStore(Repository repository) {
 | 
			
		||||
    LOG.debug("remove all blobs from store, because corresponding git repository {} was removed", repository.getName());
 | 
			
		||||
    BlobStore blobStore = lfsBlobStoreFactory.getLfsBlobStore(repository);
 | 
			
		||||
    for ( Blob blob : blobStore.getAll() ) {
 | 
			
		||||
      LOG.trace("remove blob {}, because repository {} was removed", blob.getId(), repository.getName());
 | 
			
		||||
      blobStore.remove(blob);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
}
 | 
			
		||||
@@ -8,13 +8,14 @@ import org.slf4j.Logger;
 | 
			
		||||
import org.slf4j.LoggerFactory;
 | 
			
		||||
import sonia.scm.repository.Repository;
 | 
			
		||||
import sonia.scm.store.BlobStore;
 | 
			
		||||
import sonia.scm.store.BlobStoreFactory;
 | 
			
		||||
import sonia.scm.util.HttpUtil;
 | 
			
		||||
import sonia.scm.web.lfs.ScmBlobLfsRepository;
 | 
			
		||||
 | 
			
		||||
import javax.inject.Inject;
 | 
			
		||||
import javax.inject.Singleton;
 | 
			
		||||
import javax.servlet.http.HttpServlet;
 | 
			
		||||
import javax.servlet.http.HttpServletRequest;
 | 
			
		||||
import sonia.scm.web.lfs.LfsBlobStoreFactory;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This factory class is a helper class to provide the {@link LfsProtocolServlet} and the {@link FileLfsServlet}
 | 
			
		||||
@@ -23,18 +24,16 @@ import javax.servlet.http.HttpServletRequest;
 | 
			
		||||
 * @since 1.54
 | 
			
		||||
 * Created by omilke on 11.05.2017.
 | 
			
		||||
 */
 | 
			
		||||
@Singleton
 | 
			
		||||
public class LfsServletFactory {
 | 
			
		||||
 | 
			
		||||
  private static final String GIT_LFS_REPOSITORY_POSTFIX = "-git-lfs";
 | 
			
		||||
 | 
			
		||||
  private static final Logger logger = LoggerFactory.getLogger(LfsServletFactory.class);
 | 
			
		||||
 | 
			
		||||
  private final BlobStoreFactory blobStoreFactory;
 | 
			
		||||
  private final LfsBlobStoreFactory lfsBlobStoreFactory;
 | 
			
		||||
 | 
			
		||||
  @Inject
 | 
			
		||||
  public LfsServletFactory(BlobStoreFactory blobStoreFactory) {
 | 
			
		||||
 | 
			
		||||
    this.blobStoreFactory = blobStoreFactory;
 | 
			
		||||
  public LfsServletFactory(LfsBlobStoreFactory lfsBlobStoreFactory) {
 | 
			
		||||
    this.lfsBlobStoreFactory = lfsBlobStoreFactory;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
@@ -45,8 +44,7 @@ public class LfsServletFactory {
 | 
			
		||||
   * @return The {@link LfsProtocolServlet} to provide the LFS Batch API for a SCM Repository.
 | 
			
		||||
   */
 | 
			
		||||
  public LfsProtocolServlet createProtocolServletFor(Repository repository, HttpServletRequest request) {
 | 
			
		||||
 | 
			
		||||
    BlobStore blobStore = getBlobStore(repository);
 | 
			
		||||
    BlobStore blobStore = lfsBlobStoreFactory.getLfsBlobStore(repository);
 | 
			
		||||
    String baseUri = buildBaseUri(repository, request);
 | 
			
		||||
 | 
			
		||||
    LargeFileRepository largeFileRepository = new ScmBlobLfsRepository(blobStore, baseUri);
 | 
			
		||||
@@ -61,8 +59,7 @@ public class LfsServletFactory {
 | 
			
		||||
   * @return The {@link FileLfsServlet} to provide the LFS Upload / Download API for a SCM Repository.
 | 
			
		||||
   */
 | 
			
		||||
  public HttpServlet createFileLfsServletFor(Repository repository, HttpServletRequest request) {
 | 
			
		||||
 | 
			
		||||
    return new ScmFileTransferServlet(getBlobStore(repository));
 | 
			
		||||
    return new ScmFileTransferServlet(lfsBlobStoreFactory.getLfsBlobStore(repository));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
@@ -73,26 +70,7 @@ public class LfsServletFactory {
 | 
			
		||||
   */
 | 
			
		||||
  @VisibleForTesting
 | 
			
		||||
  static String buildBaseUri(Repository repository, HttpServletRequest request) {
 | 
			
		||||
 | 
			
		||||
    return String.format("%s/git/%s.git/info/lfs/objects/", HttpUtil.getCompleteUrl(request), repository.getName());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Provides a {@link BlobStore} corresponding to the SCM Repository.
 | 
			
		||||
   * <p>
 | 
			
		||||
   * git-lfs repositories should generally carry the same name as their regular SCM repository counterparts. However,
 | 
			
		||||
   * we have decided to store them under their IDs instead of their names, since the names might change and provide
 | 
			
		||||
   * other drawbacks, as well.
 | 
			
		||||
   * <p>
 | 
			
		||||
   * These repositories will have {@linkplain #GIT_LFS_REPOSITORY_POSTFIX} appended to their IDs.
 | 
			
		||||
   *
 | 
			
		||||
   * @param repository The SCM Repository to provide a LFS {@link BlobStore} for.
 | 
			
		||||
   */
 | 
			
		||||
  @VisibleForTesting
 | 
			
		||||
  BlobStore getBlobStore(Repository repository) {
 | 
			
		||||
 | 
			
		||||
    return blobStoreFactory.getBlobStore(repository.getId() + GIT_LFS_REPOSITORY_POSTFIX);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user