blob: 0e213387e475fc7cb1aec32aa93ffc7d73e5d874 [file] [log] [blame]
// Copyright (C) 2020 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.gerritforge.gerrit.globalrefdb.validation;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableSet;
import com.google.gerrit.entities.Project;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.LocalDiskRepositoryManager;
import com.google.gerrit.server.git.RepositoryCaseMismatchException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
import java.io.IOException;
import java.util.SortedSet;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.lib.Repository;
/**
* Implements a {@link GitRepositoryManager} interface with the intent of managing repository access
* and repository creation through instances of {@link SharedRefDbRepository}, which can therefore
* validate operations on the repository itself against the global refdb
*/
@Singleton
public class SharedRefDbGitRepositoryManager implements GitRepositoryManager {
/**
* This value must be used for the named injection binding provided by libModules that want to
* define refs that should not be validated against the global refdb. For example:
*
* <pre>
* bind(new TypeLiteral&lt;ImmutableSet&lt;String&gt;&gt;() {})
* .annotatedWith(Names.named(SharedRefDbGitRepositoryManager.IGNORED_REFS))
* .toInstance(
* ImmutableSet.of(
* "refs/foo/bar",
* "refs/foo/baz"));
* </pre>
*/
public static final String IGNORED_REFS = "ignored_refs";
@Inject(optional = true)
@Named("LocalDiskRepositoryManager")
private GitRepositoryManager gitRepositoryManager;
private final LocalDiskRepositoryManager localDiskRepositoryManager;
private final SharedRefDbRepository.Factory sharedRefDbRepoFactory;
@Inject(optional = true)
@Named(IGNORED_REFS)
private ImmutableSet<String> ignoredRefs = ImmutableSet.of();
/**
* Constructs a {@code SharedRefDbGitRepositoryManager} that can create and open Git repositories
* by wrapping them in a {@code SharedRefDbRepository} object, so that operations on them can be
* validated against a global refdb
*
* @param sharedRefDbRepoFactory a factory providing a {@link SharedRefDbRepository} instance
* @param localDiskRepositoryManager an instance to manage repositories stored on the local file
* system
*/
@Inject
public SharedRefDbGitRepositoryManager(
SharedRefDbRepository.Factory sharedRefDbRepoFactory,
LocalDiskRepositoryManager localDiskRepositoryManager) {
this.sharedRefDbRepoFactory = sharedRefDbRepoFactory;
this.localDiskRepositoryManager = localDiskRepositoryManager;
}
/**
* Get (or open) a {@link Repository} by name.
*
* @param name the repository name, relative to the base directory.
* @return the repository instance
* @throws RepositoryNotFoundException the name does not denote an existing repository.
* @throws IOException the name cannot be read as a repository.
*/
@Override
public Repository openRepository(Project.NameKey name)
throws RepositoryNotFoundException, IOException {
return wrap(name, repositoryManager().openRepository(name));
}
/**
* Create (and open) a {@link Repository} by name.
*
* @param name the repository name, relative to the base directory.
* @return the repository instance
* @throws RepositoryCaseMismatchException the name collides with an existing repository name, but
* only in case of a character within the name.
* @throws RepositoryNotFoundException the name is invalid.
* @throws IOException the repository cannot be created.
*/
@Override
public Repository createRepository(Project.NameKey name)
throws RepositoryCaseMismatchException, RepositoryNotFoundException, IOException {
return wrap(name, repositoryManager().createRepository(name));
}
@Override
public SortedSet<Project.NameKey> list() {
return repositoryManager().list();
}
private Repository wrap(Project.NameKey projectName, Repository projectRepo) {
return sharedRefDbRepoFactory.create(projectName.get(), projectRepo, ignoredRefs);
}
private GitRepositoryManager repositoryManager() {
return MoreObjects.firstNonNull(gitRepositoryManager, localDiskRepositoryManager);
}
}