blob: 96e83505b5ae4328ac298febc87e2db7a9f806bc [file] [log] [blame]
// Copyright (C) 2024 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.googlesource.gerrit.plugins.gitrepometrics.collectors;
import static com.google.gerrit.entities.RefNames.REFS_USERS;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.common.flogger.FluentLogger;
import com.google.inject.Inject;
import com.googlesource.gerrit.plugins.gitrepometrics.UpdateGitMetricsExecutor;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Comparator;
import java.util.HashMap;
import java.util.concurrent.ExecutorService;
import java.util.function.Consumer;
import org.eclipse.jgit.internal.storage.file.FileRepository;
import org.eclipse.jgit.lib.Ref;
public class GitRefsMetricsCollector implements MetricsCollector {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
@VisibleForTesting
protected static final GitRepoMetric combinedRefsSha1 =
new GitRepoMetric("combinedRefsSha1", "Numeric value of combined refs SHA-1's", "Number");
private static final ImmutableList<GitRepoMetric> availableMetrics =
ImmutableList.of(combinedRefsSha1);
private final ExecutorService executorService;
@Inject
GitRefsMetricsCollector(@UpdateGitMetricsExecutor ExecutorService executorService) {
this.executorService = executorService;
}
@Override
public void collect(
FileRepository repository,
String projectName,
Consumer<HashMap<GitRepoMetric, Long>> populateMetrics) {
executorService.submit(
() -> {
try {
MessageDigest md = MessageDigest.getInstance("SHA-1");
repository.getRefDatabase().getRefs().stream()
.filter(ref -> !ref.isSymbolic() && !ref.getName().startsWith(REFS_USERS))
.sorted(Comparator.comparing(Ref::getName))
.forEach(ref -> md.update(ref.getObjectId().toString().getBytes(UTF_8)));
int sha1Int = truncateHashToInt(md.digest());
HashMap<GitRepoMetric, Long> metrics = new HashMap<>();
metrics.put(combinedRefsSha1, (long) sha1Int);
populateMetrics.accept(metrics);
} catch (NoSuchAlgorithmException e) {
logger.atSevere().withCause(e).log(
"Could not obtain SHA-1 implementation will not compute the combinedRefsSha1 metric");
} catch (IOException e) {
logger.atSevere().withCause(e).log(
"Computing combinedRefsSha1 failed. Will retry next time");
}
});
}
@Override
public String getMetricsCollectorName() {
return "repo-ref-statistics";
}
@Override
public ImmutableList<GitRepoMetric> availableMetrics() {
return availableMetrics;
}
// Source
// http://www.java2s.com/example/java-utility-method/sha1/sha1hashint-string-text-d6c0e.html
private static int truncateHashToInt(byte[] bytes) {
int offset = bytes[bytes.length - 1] & 0x0f;
return (bytes[offset] & (0x7f << 24))
| (bytes[offset + 1] & (0xff << 16))
| (bytes[offset + 2] & (0xff << 8))
| (bytes[offset + 3] & 0xff);
}
}