mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-18 03:01:05 +01:00
Repository export read-only lock (#1519)
* Lock repository for read-only access only while exporting * Create read-only check api Co-authored-by: René Pfeuffer <rene.pfeuffer@cloudogu.com>
This commit is contained in:
@@ -58,6 +58,7 @@ public class RepositoryDto extends HalRepresentation implements CreateRepository
|
||||
@NotEmpty
|
||||
private String type;
|
||||
private boolean archived;
|
||||
private boolean exporting;
|
||||
|
||||
RepositoryDto(Links links, Embedded embedded) {
|
||||
super(links, embedded);
|
||||
|
||||
@@ -161,12 +161,7 @@ public class RepositoryExportResource {
|
||||
@PathParam("name") String name
|
||||
) {
|
||||
Repository repository = getVerifiedRepository(namespace, name);
|
||||
StreamingOutput output = os -> fullScmRepositoryExporter.export(repository, os);
|
||||
|
||||
return Response
|
||||
.ok(output, "application/x-gzip")
|
||||
.header("content-disposition", createContentDispositionHeaderValue(repository, "tar.gz"))
|
||||
.build();
|
||||
return exportFullRepository(repository);
|
||||
}
|
||||
|
||||
private Repository getVerifiedRepository(String namespace, String name) {
|
||||
@@ -186,6 +181,15 @@ public class RepositoryExportResource {
|
||||
return repository;
|
||||
}
|
||||
|
||||
private Response exportFullRepository(Repository repository) {
|
||||
StreamingOutput output = os -> fullScmRepositoryExporter.export(repository, os);
|
||||
|
||||
return Response
|
||||
.ok(output, "application/x-gzip")
|
||||
.header("content-disposition", createContentDispositionHeaderValue(repository, "tar.gz"))
|
||||
.build();
|
||||
}
|
||||
|
||||
private Response exportRepository(Repository repository, boolean compressed) {
|
||||
StreamingOutput output;
|
||||
String fileExtension;
|
||||
|
||||
@@ -27,9 +27,12 @@ package sonia.scm.api.v2.resources;
|
||||
import de.otto.edison.hal.Embedded;
|
||||
import de.otto.edison.hal.Link;
|
||||
import de.otto.edison.hal.Links;
|
||||
import org.mapstruct.AfterMapping;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.MappingTarget;
|
||||
import org.mapstruct.ObjectFactory;
|
||||
import sonia.scm.config.ScmConfiguration;
|
||||
import sonia.scm.repository.DefaultRepositoryExportingCheck;
|
||||
import sonia.scm.repository.Feature;
|
||||
import sonia.scm.repository.HealthCheckFailure;
|
||||
import sonia.scm.repository.NamespaceStrategy;
|
||||
@@ -70,6 +73,11 @@ public abstract class RepositoryToRepositoryDtoMapper extends BaseMapper<Reposit
|
||||
@Override
|
||||
public abstract RepositoryDto map(Repository modelObject);
|
||||
|
||||
@AfterMapping
|
||||
void setExporting(Repository repository, @MappingTarget RepositoryDto repositoryDto) {
|
||||
repositoryDto.setExporting(DefaultRepositoryExportingCheck.isRepositoryExporting(repository.getId()));
|
||||
}
|
||||
|
||||
@ObjectFactory
|
||||
RepositoryDto createDto(Repository repository) {
|
||||
Links.Builder linksBuilder = linkingTo().self(resourceLinks.repository().self(repository.getNamespace(), repository.getName()));
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
|
||||
import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;
|
||||
import sonia.scm.ContextEntry;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.RepositoryExportingCheck;
|
||||
import sonia.scm.repository.api.ExportFailedException;
|
||||
import sonia.scm.repository.api.RepositoryService;
|
||||
import sonia.scm.repository.api.RepositoryServiceFactory;
|
||||
@@ -54,25 +55,36 @@ public class FullScmRepositoryExporter {
|
||||
private final RepositoryServiceFactory serviceFactory;
|
||||
private final TarArchiveRepositoryStoreExporter storeExporter;
|
||||
private final WorkdirProvider workdirProvider;
|
||||
private final RepositoryExportingCheck repositoryExportingCheck;
|
||||
|
||||
@Inject
|
||||
public FullScmRepositoryExporter(EnvironmentInformationXmlGenerator environmentGenerator,
|
||||
RepositoryMetadataXmlGenerator metadataGenerator,
|
||||
RepositoryServiceFactory serviceFactory,
|
||||
TarArchiveRepositoryStoreExporter storeExporter, WorkdirProvider workdirProvider) {
|
||||
TarArchiveRepositoryStoreExporter storeExporter,
|
||||
WorkdirProvider workdirProvider,
|
||||
RepositoryExportingCheck repositoryExportingCheck) {
|
||||
this.environmentGenerator = environmentGenerator;
|
||||
this.metadataGenerator = metadataGenerator;
|
||||
this.serviceFactory = serviceFactory;
|
||||
this.storeExporter = storeExporter;
|
||||
this.workdirProvider = workdirProvider;
|
||||
this.repositoryExportingCheck = repositoryExportingCheck;
|
||||
}
|
||||
|
||||
public void export(Repository repository, OutputStream outputStream) {
|
||||
repositoryExportingCheck.withExportingLock(repository, () -> {
|
||||
exportInLock(repository, outputStream);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
private void exportInLock(Repository repository, OutputStream outputStream) {
|
||||
try (
|
||||
RepositoryService service = serviceFactory.create(repository);
|
||||
BufferedOutputStream bos = new BufferedOutputStream(outputStream);
|
||||
GzipCompressorOutputStream gzos = new GzipCompressorOutputStream(bos);
|
||||
TarArchiveOutputStream taos = new TarArchiveOutputStream(gzos);
|
||||
TarArchiveOutputStream taos = new TarArchiveOutputStream(gzos)
|
||||
) {
|
||||
writeEnvironmentData(taos);
|
||||
writeMetadata(repository, taos);
|
||||
|
||||
@@ -36,8 +36,10 @@ import sonia.scm.io.FileSystem;
|
||||
import sonia.scm.lifecycle.DefaultRestarter;
|
||||
import sonia.scm.lifecycle.Restarter;
|
||||
import sonia.scm.plugin.PluginLoader;
|
||||
import sonia.scm.repository.DefaultRepositoryExportingCheck;
|
||||
import sonia.scm.repository.EventDrivenRepositoryArchiveCheck;
|
||||
import sonia.scm.repository.RepositoryArchivedCheck;
|
||||
import sonia.scm.repository.RepositoryExportingCheck;
|
||||
import sonia.scm.repository.RepositoryLocationResolver;
|
||||
import sonia.scm.repository.xml.MetadataStore;
|
||||
import sonia.scm.repository.xml.PathBasedRepositoryLocationResolver;
|
||||
@@ -100,6 +102,7 @@ public class BootstrapModule extends AbstractModule {
|
||||
|
||||
// bind core
|
||||
bind(RepositoryArchivedCheck.class, EventDrivenRepositoryArchiveCheck.class);
|
||||
bind(RepositoryExportingCheck.class, DefaultRepositoryExportingCheck.class);
|
||||
bind(ConfigurationStoreFactory.class, JAXBConfigurationStoreFactory.class);
|
||||
bind(ConfigurationEntryStoreFactory.class, JAXBConfigurationEntryStoreFactory.class);
|
||||
bind(DataStoreFactory.class, JAXBDataStoreFactory.class);
|
||||
|
||||
@@ -39,7 +39,6 @@ import sonia.scm.NoChangesMadeException;
|
||||
import sonia.scm.NotFoundException;
|
||||
import sonia.scm.SCMContextProvider;
|
||||
import sonia.scm.Type;
|
||||
import sonia.scm.config.ScmConfiguration;
|
||||
import sonia.scm.event.ScmEventBus;
|
||||
import sonia.scm.security.AuthorizationChangedEvent;
|
||||
import sonia.scm.security.KeyGenerator;
|
||||
@@ -79,7 +78,6 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager {
|
||||
private static final String THREAD_NAME = "Hook-%s";
|
||||
private static final Logger logger =
|
||||
LoggerFactory.getLogger(DefaultRepositoryManager.class);
|
||||
private final ScmConfiguration configuration;
|
||||
private final ExecutorService executorService;
|
||||
private final Map<String, RepositoryHandler> handlerMap;
|
||||
private final KeyGenerator keyGenerator;
|
||||
@@ -89,11 +87,9 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager {
|
||||
private final ManagerDaoAdapter<Repository> managerDaoAdapter;
|
||||
|
||||
@Inject
|
||||
public DefaultRepositoryManager(ScmConfiguration configuration,
|
||||
SCMContextProvider contextProvider, KeyGenerator keyGenerator,
|
||||
public DefaultRepositoryManager(SCMContextProvider contextProvider, KeyGenerator keyGenerator,
|
||||
RepositoryDAO repositoryDAO, Set<RepositoryHandler> handlerSet,
|
||||
Provider<NamespaceStrategy> namespaceStrategyProvider) {
|
||||
this.configuration = configuration;
|
||||
this.keyGenerator = keyGenerator;
|
||||
this.repositoryDAO = repositoryDAO;
|
||||
this.namespaceStrategyProvider = namespaceStrategyProvider;
|
||||
|
||||
Reference in New Issue
Block a user