From f7a4dd03560d10d504f63b9e2caeb32a6bf2cc0b Mon Sep 17 00:00:00 2001 From: Jacek Centkowski Date: Mon, 11 Nov 2024 12:36:03 +0100 Subject: Rename numberOfPackFilesAfterBitmap to numberOfPackFilesSinceBitmap As sugested in I608011462f1. Change-Id: If66226dd7b08ae768413fa614df5dcb6b44dc118 --- ...NumberOfPackFilesAfterBitmapStatisticsTest.java | 173 --------------------- ...NumberOfPackFilesSinceBitmapStatisticsTest.java | 173 +++++++++++++++++++++ 2 files changed, 173 insertions(+), 173 deletions(-) delete mode 100644 org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcNumberOfPackFilesAfterBitmapStatisticsTest.java create mode 100644 org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcNumberOfPackFilesSinceBitmapStatisticsTest.java (limited to 'org.eclipse.jgit.test/tst/org/eclipse/jgit') diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcNumberOfPackFilesAfterBitmapStatisticsTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcNumberOfPackFilesAfterBitmapStatisticsTest.java deleted file mode 100644 index e5a391f2e3..0000000000 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcNumberOfPackFilesAfterBitmapStatisticsTest.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (c) 2024 Jacek Centkowski and others. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Distribution License v. 1.0 which is available at - * https://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -package org.eclipse.jgit.internal.storage.file; - -import static org.junit.Assert.assertEquals; - -import java.io.BufferedOutputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.nio.file.Files; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.StreamSupport; - -import org.eclipse.jgit.internal.storage.file.PackIndex.MutableEntry; -import org.eclipse.jgit.internal.storage.pack.PackExt; -import org.eclipse.jgit.internal.storage.pack.PackWriter; -import org.eclipse.jgit.junit.TestRepository; -import org.eclipse.jgit.lib.NullProgressMonitor; -import org.eclipse.jgit.lib.ObjectId; -import org.eclipse.jgit.lib.PersonIdent; -import org.eclipse.jgit.lib.Ref; -import org.eclipse.jgit.revwalk.RevCommit; -import org.eclipse.jgit.util.FileUtils; -import org.junit.Test; - -public class GcNumberOfPackFilesAfterBitmapStatisticsTest extends GcTestCase { - @Test - public void testShouldReportZeroObjectsForInitializedRepo() - throws IOException { - assertEquals(0L, gc.getStatistics().numberOfPackFilesAfterBitmap); - } - - @Test - public void testShouldReportAllPackFilesWhenNoGcWasPerformed() - throws Exception { - packAndPrune(); - long result = gc.getStatistics().numberOfPackFilesAfterBitmap; - - assertEquals(repo.getObjectDatabase().getPacks().size(), result); - } - - @Test - public void testShouldReportNoObjectsDirectlyAfterGc() throws Exception { - // given - addCommit(null); - gc.gc().get(); - assertEquals(1L, repositoryBitmapFiles()); - assertEquals(0L, gc.getStatistics().numberOfPackFilesAfterBitmap); - } - - @Test - public void testShouldReportNewObjectsAfterGcWhenRepositoryProgresses() - throws Exception { - // commit & gc - RevCommit parent = addCommit(null); - gc.gc().get(); - assertEquals(1L, repositoryBitmapFiles()); - - // progress & pack - addCommit(parent); - packAndPrune(); - - assertEquals(1L, gc.getStatistics().numberOfPackFilesAfterBitmap); - } - - @Test - public void testShouldReportNewObjectsFromTheLatestBitmapWhenRepositoryProgresses() - throws Exception { - // commit & gc - RevCommit parent = addCommit(null); - gc.gc().get(); - assertEquals(1L, repositoryBitmapFiles()); - - // progress & gc - parent = addCommit(parent); - gc.gc().get(); - assertEquals(2L, repositoryBitmapFiles()); - - // progress & pack - addCommit(parent); - packAndPrune(); - - assertEquals(1L, gc.getStatistics().numberOfPackFilesAfterBitmap); - } - - private void packAndPrune() throws Exception { - try (SkipNonExistingFilesTestRepository testRepo = new SkipNonExistingFilesTestRepository( - repo)) { - testRepo.packAndPrune(); - } - } - - private RevCommit addCommit(RevCommit parent) throws Exception { - return tr.branch("master").commit() - .author(new PersonIdent("repo-metrics", "repo@metrics.com")) - .parent(parent).create(); - } - - private long repositoryBitmapFiles() throws IOException { - return StreamSupport - .stream(Files - .newDirectoryStream(repo.getObjectDatabase() - .getPackDirectory().toPath(), "pack-*.bitmap") - .spliterator(), false) - .count(); - } - - /** - * The TestRepository has a {@link TestRepository#packAndPrune()} function - * but it fails in the last step after GC was performed as it doesn't - * SKIP_MISSING files. In order to circumvent it was copied and improved - * here. - */ - private static class SkipNonExistingFilesTestRepository - extends TestRepository { - private final FileRepository repo; - - private SkipNonExistingFilesTestRepository(FileRepository db) throws IOException { - super(db); - repo = db; - } - - @Override - public void packAndPrune() throws Exception { - ObjectDirectory odb = repo.getObjectDatabase(); - NullProgressMonitor m = NullProgressMonitor.INSTANCE; - - final PackFile pack, idx; - try (PackWriter pw = new PackWriter(repo)) { - Set all = new HashSet<>(); - for (Ref r : repo.getRefDatabase().getRefs()) - all.add(r.getObjectId()); - pw.preparePack(m, all, PackWriter.NONE); - - pack = new PackFile(odb.getPackDirectory(), pw.computeName(), - PackExt.PACK); - try (OutputStream out = new BufferedOutputStream( - new FileOutputStream(pack))) { - pw.writePack(m, m, out); - } - pack.setReadOnly(); - - idx = pack.create(PackExt.INDEX); - try (OutputStream out = new BufferedOutputStream( - new FileOutputStream(idx))) { - pw.writeIndex(out); - } - idx.setReadOnly(); - } - - odb.openPack(pack); - updateServerInfo(); - - // alternative packAndPrune implementation that skips missing files - // after GC. - for (Pack p : odb.getPacks()) { - for (MutableEntry e : p) - FileUtils.delete(odb.fileFor(e.toObjectId()), - FileUtils.SKIP_MISSING); - } - } - } -} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcNumberOfPackFilesSinceBitmapStatisticsTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcNumberOfPackFilesSinceBitmapStatisticsTest.java new file mode 100644 index 0000000000..42cb3cd0c2 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcNumberOfPackFilesSinceBitmapStatisticsTest.java @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2024 Jacek Centkowski and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.internal.storage.file; + +import static org.junit.Assert.assertEquals; + +import java.io.BufferedOutputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Files; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.StreamSupport; + +import org.eclipse.jgit.internal.storage.file.PackIndex.MutableEntry; +import org.eclipse.jgit.internal.storage.pack.PackExt; +import org.eclipse.jgit.internal.storage.pack.PackWriter; +import org.eclipse.jgit.junit.TestRepository; +import org.eclipse.jgit.lib.NullProgressMonitor; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.util.FileUtils; +import org.junit.Test; + +public class GcNumberOfPackFilesSinceBitmapStatisticsTest extends GcTestCase { + @Test + public void testShouldReportZeroObjectsForInitializedRepo() + throws IOException { + assertEquals(0L, gc.getStatistics().numberOfPackFilesSinceBitmap); + } + + @Test + public void testShouldReportAllPackFilesWhenNoGcWasPerformed() + throws Exception { + packAndPrune(); + long result = gc.getStatistics().numberOfPackFilesSinceBitmap; + + assertEquals(repo.getObjectDatabase().getPacks().size(), result); + } + + @Test + public void testShouldReportNoObjectsDirectlyAfterGc() throws Exception { + // given + addCommit(null); + gc.gc().get(); + assertEquals(1L, repositoryBitmapFiles()); + assertEquals(0L, gc.getStatistics().numberOfPackFilesSinceBitmap); + } + + @Test + public void testShouldReportNewObjectsSinceGcWhenRepositoryProgresses() + throws Exception { + // commit & gc + RevCommit parent = addCommit(null); + gc.gc().get(); + assertEquals(1L, repositoryBitmapFiles()); + + // progress & pack + addCommit(parent); + packAndPrune(); + + assertEquals(1L, gc.getStatistics().numberOfPackFilesSinceBitmap); + } + + @Test + public void testShouldReportNewObjectsFromTheLatestBitmapWhenRepositoryProgresses() + throws Exception { + // commit & gc + RevCommit parent = addCommit(null); + gc.gc().get(); + assertEquals(1L, repositoryBitmapFiles()); + + // progress & gc + parent = addCommit(parent); + gc.gc().get(); + assertEquals(2L, repositoryBitmapFiles()); + + // progress & pack + addCommit(parent); + packAndPrune(); + + assertEquals(1L, gc.getStatistics().numberOfPackFilesSinceBitmap); + } + + private void packAndPrune() throws Exception { + try (SkipNonExistingFilesTestRepository testRepo = new SkipNonExistingFilesTestRepository( + repo)) { + testRepo.packAndPrune(); + } + } + + private RevCommit addCommit(RevCommit parent) throws Exception { + return tr.branch("master").commit() + .author(new PersonIdent("repo-metrics", "repo@metrics.com")) + .parent(parent).create(); + } + + private long repositoryBitmapFiles() throws IOException { + return StreamSupport + .stream(Files + .newDirectoryStream(repo.getObjectDatabase() + .getPackDirectory().toPath(), "pack-*.bitmap") + .spliterator(), false) + .count(); + } + + /** + * The TestRepository has a {@link TestRepository#packAndPrune()} function + * but it fails in the last step after GC was performed as it doesn't + * SKIP_MISSING files. In order to circumvent it was copied and improved + * here. + */ + private static class SkipNonExistingFilesTestRepository + extends TestRepository { + private final FileRepository repo; + + private SkipNonExistingFilesTestRepository(FileRepository db) throws IOException { + super(db); + repo = db; + } + + @Override + public void packAndPrune() throws Exception { + ObjectDirectory odb = repo.getObjectDatabase(); + NullProgressMonitor m = NullProgressMonitor.INSTANCE; + + final PackFile pack, idx; + try (PackWriter pw = new PackWriter(repo)) { + Set all = new HashSet<>(); + for (Ref r : repo.getRefDatabase().getRefs()) + all.add(r.getObjectId()); + pw.preparePack(m, all, PackWriter.NONE); + + pack = new PackFile(odb.getPackDirectory(), pw.computeName(), + PackExt.PACK); + try (OutputStream out = new BufferedOutputStream( + new FileOutputStream(pack))) { + pw.writePack(m, m, out); + } + pack.setReadOnly(); + + idx = pack.create(PackExt.INDEX); + try (OutputStream out = new BufferedOutputStream( + new FileOutputStream(idx))) { + pw.writeIndex(out); + } + idx.setReadOnly(); + } + + odb.openPack(pack); + updateServerInfo(); + + // alternative packAndPrune implementation that skips missing files + // after GC. + for (Pack p : odb.getPacks()) { + for (MutableEntry e : p) + FileUtils.delete(odb.fileFor(e.toObjectId()), + FileUtils.SKIP_MISSING); + } + } + } +} -- cgit v1.2.3 From 592a75800543f83486211b2191707f21695eb955 Mon Sep 17 00:00:00 2001 From: Jacek Centkowski Date: Mon, 11 Nov 2024 12:48:20 +0100 Subject: Don't fail when trying to prune pack which is already gone Update the TestRepository.prunePacked so that it doesn't fail if a pack to be pruned is already gone. It is especially handy when the prunePacked function is called in `TestRepository.packAndPrune` function after the repo moves on after GC was performed. Change-Id: I01b4ddbaddec1fdc24cfbb967e0edfe0de6c4b7c --- .../src/org/eclipse/jgit/junit/TestRepository.java | 3 +- ...NumberOfPackFilesSinceBitmapStatisticsTest.java | 82 +--------------------- 2 files changed, 5 insertions(+), 80 deletions(-) (limited to 'org.eclipse.jgit.test/tst/org/eclipse/jgit') diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java index 66cf739ef1..c6cdfafe84 100644 --- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java +++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java @@ -1020,7 +1020,8 @@ public class TestRepository implements AutoCloseable { private static void prunePacked(ObjectDirectory odb) throws IOException { for (Pack p : odb.getPacks()) { for (MutableEntry e : p) - FileUtils.delete(odb.fileFor(e.toObjectId())); + FileUtils.delete(odb.fileFor(e.toObjectId()), + FileUtils.SKIP_MISSING); } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcNumberOfPackFilesSinceBitmapStatisticsTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcNumberOfPackFilesSinceBitmapStatisticsTest.java index 42cb3cd0c2..fa13bb57c8 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcNumberOfPackFilesSinceBitmapStatisticsTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcNumberOfPackFilesSinceBitmapStatisticsTest.java @@ -12,25 +12,12 @@ package org.eclipse.jgit.internal.storage.file; import static org.junit.Assert.assertEquals; -import java.io.BufferedOutputStream; -import java.io.FileOutputStream; import java.io.IOException; -import java.io.OutputStream; import java.nio.file.Files; -import java.util.HashSet; -import java.util.Set; import java.util.stream.StreamSupport; -import org.eclipse.jgit.internal.storage.file.PackIndex.MutableEntry; -import org.eclipse.jgit.internal.storage.pack.PackExt; -import org.eclipse.jgit.internal.storage.pack.PackWriter; -import org.eclipse.jgit.junit.TestRepository; -import org.eclipse.jgit.lib.NullProgressMonitor; -import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.PersonIdent; -import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.revwalk.RevCommit; -import org.eclipse.jgit.util.FileUtils; import org.junit.Test; public class GcNumberOfPackFilesSinceBitmapStatisticsTest extends GcTestCase { @@ -43,7 +30,7 @@ public class GcNumberOfPackFilesSinceBitmapStatisticsTest extends GcTestCase { @Test public void testShouldReportAllPackFilesWhenNoGcWasPerformed() throws Exception { - packAndPrune(); + tr.packAndPrune(); long result = gc.getStatistics().numberOfPackFilesSinceBitmap; assertEquals(repo.getObjectDatabase().getPacks().size(), result); @@ -68,7 +55,7 @@ public class GcNumberOfPackFilesSinceBitmapStatisticsTest extends GcTestCase { // progress & pack addCommit(parent); - packAndPrune(); + tr.packAndPrune(); assertEquals(1L, gc.getStatistics().numberOfPackFilesSinceBitmap); } @@ -88,18 +75,11 @@ public class GcNumberOfPackFilesSinceBitmapStatisticsTest extends GcTestCase { // progress & pack addCommit(parent); - packAndPrune(); + tr.packAndPrune(); assertEquals(1L, gc.getStatistics().numberOfPackFilesSinceBitmap); } - private void packAndPrune() throws Exception { - try (SkipNonExistingFilesTestRepository testRepo = new SkipNonExistingFilesTestRepository( - repo)) { - testRepo.packAndPrune(); - } - } - private RevCommit addCommit(RevCommit parent) throws Exception { return tr.branch("master").commit() .author(new PersonIdent("repo-metrics", "repo@metrics.com")) @@ -114,60 +94,4 @@ public class GcNumberOfPackFilesSinceBitmapStatisticsTest extends GcTestCase { .spliterator(), false) .count(); } - - /** - * The TestRepository has a {@link TestRepository#packAndPrune()} function - * but it fails in the last step after GC was performed as it doesn't - * SKIP_MISSING files. In order to circumvent it was copied and improved - * here. - */ - private static class SkipNonExistingFilesTestRepository - extends TestRepository { - private final FileRepository repo; - - private SkipNonExistingFilesTestRepository(FileRepository db) throws IOException { - super(db); - repo = db; - } - - @Override - public void packAndPrune() throws Exception { - ObjectDirectory odb = repo.getObjectDatabase(); - NullProgressMonitor m = NullProgressMonitor.INSTANCE; - - final PackFile pack, idx; - try (PackWriter pw = new PackWriter(repo)) { - Set all = new HashSet<>(); - for (Ref r : repo.getRefDatabase().getRefs()) - all.add(r.getObjectId()); - pw.preparePack(m, all, PackWriter.NONE); - - pack = new PackFile(odb.getPackDirectory(), pw.computeName(), - PackExt.PACK); - try (OutputStream out = new BufferedOutputStream( - new FileOutputStream(pack))) { - pw.writePack(m, m, out); - } - pack.setReadOnly(); - - idx = pack.create(PackExt.INDEX); - try (OutputStream out = new BufferedOutputStream( - new FileOutputStream(idx))) { - pw.writeIndex(out); - } - idx.setReadOnly(); - } - - odb.openPack(pack); - updateServerInfo(); - - // alternative packAndPrune implementation that skips missing files - // after GC. - for (Pack p : odb.getPacks()) { - for (MutableEntry e : p) - FileUtils.delete(odb.fileFor(e.toObjectId()), - FileUtils.SKIP_MISSING); - } - } - } } -- cgit v1.2.3 From 4b3c5194acd8a9b18bf269888cab2ea29c376508 Mon Sep 17 00:00:00 2001 From: Kaushik Lingarkar Date: Tue, 19 Nov 2024 09:37:33 -0800 Subject: Support built-in diff drivers for hunk header function names The regexes defined for each built-in driver will be used to determine the function name for a hunk header. Each driver can specify a list of regexes to negate and match. They can also define pattern compilation flags if needed. These drivers only apply to text files with unified patch type. Following built-in drivers have been added: - cpp - dts - java - python - rust Support for more languages can be added as needed to match the cgit implementation. Change-Id: Ice5430bfed7e4aaf9f00e52e44402479984953c5 --- .../org/eclipse/jgit/test/resources/greeting.c | 43 +++++ .../jgit/test/resources/greeting.javasource | 37 +++++ .../org/eclipse/jgit/test/resources/greeting.py | 26 ++++ .../org/eclipse/jgit/test/resources/greeting.rs | 27 ++++ .../org/eclipse/jgit/test/resources/sample.dtsi | 25 +++ .../jgit/diff/DiffFormatterBuiltInDriverTest.java | 173 +++++++++++++++++++++ org.eclipse.jgit/.settings/.api_filters | 28 ++++ .../src/org/eclipse/jgit/diff/DiffDriver.java | 116 ++++++++++++++ .../src/org/eclipse/jgit/diff/DiffFormatter.java | 140 +++++++++++++++-- .../eclipse/jgit/diff/PatchIdDiffFormatter.java | 4 +- 10 files changed, 606 insertions(+), 13 deletions(-) create mode 100644 org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/greeting.c create mode 100644 org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/greeting.javasource create mode 100644 org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/greeting.py create mode 100644 org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/greeting.rs create mode 100644 org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/sample.dtsi create mode 100644 org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterBuiltInDriverTest.java create mode 100644 org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffDriver.java (limited to 'org.eclipse.jgit.test/tst/org/eclipse/jgit') diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/greeting.c b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/greeting.c new file mode 100644 index 0000000000..3661160921 --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/greeting.c @@ -0,0 +1,43 @@ +#include +#include +#include + +void getGreeting(char *result, const char *name) { + sprintf(result, "Hello, %s!", name); +} + +void getFarewell(char *result, const char *name) { + sprintf(result, "Goodbye, %s. Have a great day!", name); +} + +void toLower(char *str) { + for (int i = 0; str[i]; i++) { + str[i] = tolower(str[i]); + } +} + +void getPersonalizedGreeting(char *result, const char *name, const char *timeOfDay) { + char timeOfDayLower[50]; + strcpy(timeOfDayLower, timeOfDay); + toLower(timeOfDayLower); + if (strcmp(timeOfDayLower, "morning") == 0) { + sprintf(result, "Good morning, %s", name); + } else if (strcmp(timeOfDayLower, "afternoon") == 0) { + sprintf(result, "Good afternoon, %s", name); + } else if (strcmp(timeOfDayLower, "evening") == 0) { + sprintf(result, "Good evening, %s", name); + } else { + sprintf(result, "Good day, %s", name); + } +} + +int main() { + char result[100]; + getGreeting(result, "foo"); + printf("%s\\n", result); + getFarewell(result, "bar"); + printf("%s\\n", result); + getPersonalizedGreeting(result, "baz", "morning"); + printf("%s\\n", result); + return 0; +} diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/greeting.javasource b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/greeting.javasource new file mode 100644 index 0000000000..9659685c63 --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/greeting.javasource @@ -0,0 +1,37 @@ +public class Greeting { + public String getGreeting(String name) { + String msg = "Hello, " + name + "!"; + return msg; + } + + public String getFarewell(String name) { + String msg = "Goodbye, " + name + ". Have a great day!"; + return msg; + } + + public String getPersonalizedGreeting(String name, String timeOfDay) { + String msg; + switch (timeOfDay.toLowerCase()) { + case "morning": + msg = "Good morning, " + name; + break; + case "afternoon": + msg = "Good afternoon, " + name; + break; + case "evening": + msg = "Good evening, " + name; + break; + default: + msg = "Good day, " + name; + break; + } + return msg; + } + + public static void main(String[] args) { + Greeting greeting = new Greeting(); + System.out.println(greeting.getGreeting("foo")); + System.out.println(greeting.getFarewell("bar")); + System.out.println(greeting.getPersonalizedGreeting("baz", "morning")); + } +} diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/greeting.py b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/greeting.py new file mode 100644 index 0000000000..9eda6cd8fe --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/greeting.py @@ -0,0 +1,26 @@ +class Greeting: + def get_greeting(self, name): + greeting_message = f"Hello, {name}!" + return greeting_message + + def get_farewell(self, name): + farewell_message = f"Goodbye, {name}. Have a great day!" + return farewell_message + + def get_personalized_greeting(self, name, time_of_day): + time_of_day = time_of_day.lower() + if time_of_day == "morning": + personalized_message = f"Good morning, {name}" + elif time_of_day == "afternoon": + personalized_message = f"Good afternoon, {name}" + elif time_of_day == "evening": + personalized_message = f"Good evening, {name}" + else: + personalized_message = f"Good day, {name}" + return personalized_message + +if __name__ == "__main__": + greeting = Greeting() + print(greeting.get_greeting("foo")) + print(greeting.get_farewell("bar")) + print(greeting.get_personalized_greeting("baz", "morning")) diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/greeting.rs b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/greeting.rs new file mode 100644 index 0000000000..a3aa5cbe7c --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/greeting.rs @@ -0,0 +1,27 @@ +struct Greeting; + +impl Greeting { + fn get_greeting(&self, name: &str) -> String { + format!("Hello, {}!", name) + } + + fn get_farewell(&self, name: &str) -> String { + format!("Goodbye, {}. Have a great day!", name) + } + + fn get_personalized_greeting(&self, name: &str, time_of_day: &str) -> String { + match time_of_day.to_lowercase().as_str() { + "morning" => format!("Good morning, {}", name), + "afternoon" => format!("Good afternoon, {}", name), + "evening" => format!("Good evening, {}", name), + _ => format!("Good day, {}", name), + } + } +} + +fn main() { + let greeting = Greeting; + println!("{}", greeting.get_greeting("foo")); + println!("{}", greeting.get_farewell("bar")); + println!("{}", greeting.get_personalized_greeting("baz", "morning")); +} diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/sample.dtsi b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/sample.dtsi new file mode 100644 index 0000000000..6aa4ecdd4c --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/sample.dtsi @@ -0,0 +1,25 @@ +/dts-v1/; + +/ { + model = "Example Board"; + compatible = "example,board"; + cpus { + cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; + reg = <0>; + }; + }; + + memory { + device_type = "memory"; + reg = <0x80000000 0x20000000>; + }; + + uart0: uart@101f1000 { + compatible = "ns16550a"; + reg = <0x101f1000 0x1000>; + interrupts = <5>; + clock-frequency = <24000000>; + }; +}; diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterBuiltInDriverTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterBuiltInDriverTest.java new file mode 100644 index 0000000000..1352871983 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterBuiltInDriverTest.java @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.diff; + +import static org.junit.Assert.assertEquals; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.stream.Collectors; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.junit.JGitTestUtil; +import org.eclipse.jgit.junit.RepositoryTestCase; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.treewalk.CanonicalTreeParser; +import org.junit.Test; + +public class DiffFormatterBuiltInDriverTest extends RepositoryTestCase { + @Test + public void testCppDriver() throws Exception { + String fileName = "greeting.c"; + String body = Files.readString( + Path.of(JGitTestUtil.getTestResourceFile(fileName) + .getAbsolutePath())); + RevCommit c1; + RevCommit c2; + try (Git git = new Git(db)) { + createCommit(git, ".gitattributes", "*.c diff=cpp"); + c1 = createCommit(git, fileName, body); + c2 = createCommit(git, fileName, + body.replace("Good day", "Greetings") + .replace("baz", "qux")); + } + try (ByteArrayOutputStream os = new ByteArrayOutputStream(); + DiffFormatter diffFormatter = new DiffFormatter(os)) { + String actual = getHunkHeaders(c1, c2, os, diffFormatter); + String expected = + "@@ -27,7 +27,7 @@ void getPersonalizedGreeting(char *result, const char *name, const char *timeOfD\n" + + "@@ -37,7 +37,7 @@ int main() {"; + assertEquals(expected, actual); + } + } + + @Test + public void testDtsDriver() throws Exception { + String fileName = "sample.dtsi"; + String body = Files.readString( + Path.of(JGitTestUtil.getTestResourceFile(fileName) + .getAbsolutePath())); + RevCommit c1; + RevCommit c2; + try (Git git = new Git(db)) { + createCommit(git, ".gitattributes", "*.dtsi diff=dts"); + c1 = createCommit(git, fileName, body); + c2 = createCommit(git, fileName, + body.replace("clock-frequency = <24000000>", + "clock-frequency = <48000000>")); + } + try (ByteArrayOutputStream os = new ByteArrayOutputStream(); + DiffFormatter diffFormatter = new DiffFormatter(os)) { + String actual = getHunkHeaders(c1, c2, os, diffFormatter); + String expected = "@@ -20,6 +20,6 @@ uart0: uart@101f1000 {"; + assertEquals(expected, actual); + } + } + + @Test + public void testJavaDriver() throws Exception { + String resourceName = "greeting.javasource"; + String body = Files.readString( + Path.of(JGitTestUtil.getTestResourceFile(resourceName) + .getAbsolutePath())); + RevCommit c1; + RevCommit c2; + try (Git git = new Git(db)) { + createCommit(git, ".gitattributes", "*.java diff=java"); + String fileName = "Greeting.java"; + c1 = createCommit(git, fileName, body); + c2 = createCommit(git, fileName, + body.replace("Good day", "Greetings") + .replace("baz", "qux")); + } + try (ByteArrayOutputStream os = new ByteArrayOutputStream(); + DiffFormatter diffFormatter = new DiffFormatter(os)) { + String actual = getHunkHeaders(c1, c2, os, diffFormatter); + String expected = + "@@ -22,7 +22,7 @@ public String getPersonalizedGreeting(String name, String timeOfDay) {\n" + + "@@ -32,6 +32,6 @@ public static void main(String[] args) {"; + assertEquals(expected, actual); + } + } + + @Test + public void testPythonDriver() throws Exception { + String fileName = "greeting.py"; + String body = Files.readString( + Path.of(JGitTestUtil.getTestResourceFile(fileName) + .getAbsolutePath())); + RevCommit c1; + RevCommit c2; + try (Git git = new Git(db)) { + createCommit(git, ".gitattributes", "*.py diff=python"); + c1 = createCommit(git, fileName, body); + c2 = createCommit(git, fileName, + body.replace("Good day", "Greetings")); + } + try (ByteArrayOutputStream os = new ByteArrayOutputStream(); + DiffFormatter diffFormatter = new DiffFormatter(os)) { + String actual = getHunkHeaders(c1, c2, os, diffFormatter); + String expected = "@@ -16,7 +16,7 @@ def get_personalized_greeting(self, name, time_of_day):"; + assertEquals(expected, actual); + } + } + + @Test + public void testRustDriver() throws Exception { + String fileName = "greeting.rs"; + String body = Files.readString( + Path.of(JGitTestUtil.getTestResourceFile(fileName) + .getAbsolutePath())); + RevCommit c1; + RevCommit c2; + try (Git git = new Git(db)) { + createCommit(git, ".gitattributes", "*.rs diff=rust"); + c1 = createCommit(git, fileName, body); + c2 = createCommit(git, fileName, + body.replace("Good day", "Greetings") + .replace("baz", "qux")); + } + try (ByteArrayOutputStream os = new ByteArrayOutputStream(); + DiffFormatter diffFormatter = new DiffFormatter(os)) { + String actual = getHunkHeaders(c1, c2, os, diffFormatter); + String expected = + "@@ -14,7 +14,7 @@ fn get_personalized_greeting(&self, name: &str, time_of_day: &str) -> String {\n" + + "@@ -23,5 +23,5 @@ fn main() {"; + assertEquals(expected, actual); + } + } + + private String getHunkHeaders(RevCommit c1, RevCommit c2, + ByteArrayOutputStream os, DiffFormatter diffFormatter) + throws IOException { + diffFormatter.setRepository(db); + diffFormatter.format(new CanonicalTreeParser(null, db.newObjectReader(), + c1.getTree()), + new CanonicalTreeParser(null, db.newObjectReader(), + c2.getTree())); + diffFormatter.flush(); + return Arrays.stream(os.toString(StandardCharsets.UTF_8).split("\n")) + .filter(line -> line.startsWith("@@")) + .collect(Collectors.joining("\n")); + } + + private RevCommit createCommit(Git git, String fileName, String body) + throws IOException, GitAPIException { + writeTrashFile(fileName, body); + git.add().addFilepattern(".").call(); + return git.commit().setMessage("message").call(); + } +} diff --git a/org.eclipse.jgit/.settings/.api_filters b/org.eclipse.jgit/.settings/.api_filters index 2c22f0231c..d3ae4cf376 100644 --- a/org.eclipse.jgit/.settings/.api_filters +++ b/org.eclipse.jgit/.settings/.api_filters @@ -1,5 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffDriver.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffDriver.java new file mode 100644 index 0000000000..9ae1aaa298 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffDriver.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.diff; + +import java.util.List; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/** + * Built-in drivers for various languages, sorted by name. These drivers will be + * used to determine function names for a hunk. + *

+ * When writing or updating patterns, assume the contents are syntactically + * correct. Patterns can be simple and need not cover all syntactical corner + * cases, as long as they are sufficiently permissive. + * + * @since 6.10.1 + */ +@SuppressWarnings({"ImmutableEnumChecker", "nls"}) +public enum DiffDriver { + /** + * Built-in diff driver for c++ + */ + cpp(List.of( + /* Jump targets or access declarations */ + "^[ \\t]*[A-Za-z_][A-Za-z_0-9]*:\\s*($|/[/*])"), List.of( + /* functions/methods, variables, and compounds at top level */ + "^((::\\s*)?[A-Za-z_].*)$")), + /** + * Built-in diff driver for device + * tree files + */ + dts(List.of(";", "="), List.of( + /* lines beginning with a word optionally preceded by '&' or the root */ + "^[ \\t]*((/[ \\t]*\\{|&?[a-zA-Z_]).*)")), + /** + * Built-in diff driver for java + */ + java(List.of( + "^[ \\t]*(catch|do|for|if|instanceof|new|return|switch|throw|while)"), + List.of( + /* Class, enum, interface, and record declarations */ + "^[ \\t]*(([a-z-]+[ \\t]+)*(class|enum|interface|record)[ \\t]+.*)$", + /* Method definitions; note that constructor signatures are not */ + /* matched because they are indistinguishable from method calls. */ + "^[ \\t]*(([A-Za-z_<>&\\]\\[][?&<>.,A-Za-z_0-9]*[ \\t]+)+[A-Za-z_]" + + "[A-Za-z_0-9]*[ \\t]*\\([^;]*)$")), + /** + * Built-in diff driver for python + */ + python(List.of("^[ \\t]*((class|(async[ \\t]+)?def)[ \\t].*)$")), + /** + * Built-in diff driver for java + */ + rust(List.of("^[\\t ]*((pub(\\([^\\)]+\\))?[\\t ]+)?" + + "((async|const|unsafe|extern([\\t ]+\"[^\"]+\"))[\\t ]+)?" + + "(struct|enum|union|mod|trait|fn|impl|macro_rules!)[< \\t]+[^;]*)$")); + + private final List negatePatterns; + + private final List matchPatterns; + + DiffDriver(List negate, List match, int flags) { + if (negate != null) { + this.negatePatterns = negate.stream() + .map(r -> Pattern.compile(r, flags)) + .collect(Collectors.toList()); + } else { + this.negatePatterns = null; + } + this.matchPatterns = match.stream().map(r -> Pattern.compile(r, flags)) + .collect(Collectors.toList()); + } + + DiffDriver(List match) { + this(null, match, 0); + } + + DiffDriver(List negate, List match) { + this(negate, match, 0); + } + + /** + * Returns the list of patterns used to exclude certain lines from being + * considered as function names. + * + * @return the list of negate patterns + */ + public List getNegatePatterns() { + return negatePatterns; + } + + /** + * Returns the list of patterns used to match lines for potential function + * names. + * + * @return the list of match patterns + */ + public List getMatchPatterns() { + return matchPatterns; + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java index 2f472b5c0a..fa446e18cd 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java @@ -30,7 +30,9 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.regex.Pattern; import org.eclipse.jgit.api.errors.CanceledException; +import org.eclipse.jgit.attributes.Attribute; import org.eclipse.jgit.diff.DiffAlgorithm.SupportedAlgorithm; import org.eclipse.jgit.diff.DiffEntry.ChangeType; import org.eclipse.jgit.dircache.DirCacheIterator; @@ -703,7 +705,7 @@ public class DiffFormatter implements AutoCloseable { */ public void format(DiffEntry ent) throws IOException { FormatResult res = createFormatResult(ent); - format(res.header, res.a, res.b); + format(res.header, res.a, res.b, getDiffDriver(ent)); } private static byte[] writeGitLinkText(AbbreviatedObjectId id) { @@ -749,11 +751,14 @@ public class DiffFormatter implements AutoCloseable { * text source for the post-image version of the content. This * must match the content of * {@link org.eclipse.jgit.patch.FileHeader#getNewId()}. + * @param diffDriver + * the diff driver used to obtain function names in hunk headers * @throws java.io.IOException - * writing to the supplied stream failed. + * writing to the supplied stream failed. + * @since 6.10.1 */ - public void format(FileHeader head, RawText a, RawText b) - throws IOException { + public void format(FileHeader head, RawText a, RawText b, + DiffDriver diffDriver) throws IOException { // Reuse the existing FileHeader as-is by blindly copying its // header lines, but avoiding its hunks. Instead we recreate // the hunks from the text instances we have been supplied. @@ -763,8 +768,49 @@ public class DiffFormatter implements AutoCloseable { if (!head.getHunks().isEmpty()) end = head.getHunks().get(0).getStartOffset(); out.write(head.getBuffer(), start, end - start); - if (head.getPatchType() == PatchType.UNIFIED) - format(head.toEditList(), a, b); + if (head.getPatchType() == PatchType.UNIFIED) { + format(head.toEditList(), a, b, diffDriver); + } + } + + /** + * Format a patch script, reusing a previously parsed FileHeader. + *

+ * This formatter is primarily useful for editing an existing patch script + * to increase or reduce the number of lines of context within the script. + * All header lines are reused as-is from the supplied FileHeader. + * + * @param head + * existing file header containing the header lines to copy. + * @param a + * text source for the pre-image version of the content. This must match + * the content of {@link org.eclipse.jgit.patch.FileHeader#getOldId()}. + * @param b + * text source for the post-image version of the content. This must match + * the content of {@link org.eclipse.jgit.patch.FileHeader#getNewId()}. + * @throws java.io.IOException + * writing to the supplied stream failed. + */ + public void format(FileHeader head, RawText a, RawText b) + throws IOException { + format(head, a, b, null); + } + + /** + * Formats a list of edits in unified diff format + * + * @param edits + * some differences which have been calculated between A and B + * @param a + * the text A which was compared + * @param b + * the text B which was compared + * @throws java.io.IOException + * if an IO error occurred + */ + public void format(EditList edits, RawText a, RawText b) + throws IOException { + format(edits, a, b, null); } /** @@ -776,11 +822,14 @@ public class DiffFormatter implements AutoCloseable { * the text A which was compared * @param b * the text B which was compared + * @param diffDriver + * the diff driver used to obtain function names in hunk headers * @throws java.io.IOException * if an IO error occurred + * @since 6.10.1 */ - public void format(EditList edits, RawText a, RawText b) - throws IOException { + public void format(EditList edits, RawText a, RawText b, + DiffDriver diffDriver) throws IOException { for (int curIdx = 0; curIdx < edits.size();) { Edit curEdit = edits.get(curIdx); final int endIdx = findCombinedEnd(edits, curIdx); @@ -791,7 +840,8 @@ public class DiffFormatter implements AutoCloseable { final int aEnd = (int) Math.min(a.size(), (long) endEdit.getEndA() + context); final int bEnd = (int) Math.min(b.size(), (long) endEdit.getEndB() + context); - writeHunkHeader(aCur, aEnd, bCur, bEnd); + writeHunkHeader(aCur, aEnd, bCur, bEnd, + getFuncName(a, aCur - 1, diffDriver)); while (aCur < aEnd || bCur < bEnd) { if (aCur < curEdit.getBeginA() || endIdx + 1 < curIdx) { @@ -881,8 +931,30 @@ public class DiffFormatter implements AutoCloseable { * @throws java.io.IOException * if an IO error occurred */ - protected void writeHunkHeader(int aStartLine, int aEndLine, - int bStartLine, int bEndLine) throws IOException { + protected void writeHunkHeader(int aStartLine, int aEndLine, int bStartLine, + int bEndLine) throws IOException { + writeHunkHeader(aStartLine, aEndLine, bStartLine, bEndLine, null); + } + + /** + * Output a hunk header + * + * @param aStartLine + * within first source + * @param aEndLine + * within first source + * @param bStartLine + * within second source + * @param bEndLine + * within second source + * @param funcName + * function name of this hunk + * @throws java.io.IOException + * if an IO error occurred + * @since 6.10.1 + */ + protected void writeHunkHeader(int aStartLine, int aEndLine, int bStartLine, + int bEndLine, String funcName) throws IOException { out.write('@'); out.write('@'); writeRange('-', aStartLine + 1, aEndLine - aStartLine); @@ -890,6 +962,10 @@ public class DiffFormatter implements AutoCloseable { out.write(' '); out.write('@'); out.write('@'); + if (funcName != null) { + out.write(' '); + out.write(funcName.getBytes()); + } out.write('\n'); } @@ -1247,4 +1323,46 @@ public class DiffFormatter implements AutoCloseable { private static boolean end(Edit edit, int a, int b) { return edit.getEndA() <= a && edit.getEndB() <= b; } + + private String getFuncName(RawText text, int startAt, + DiffDriver diffDriver) { + if (diffDriver != null) { + while (startAt > 0) { + String line = text.getString(startAt); + startAt--; + if (matchesAny(diffDriver.getNegatePatterns(), line)) { + continue; + } + if (matchesAny(diffDriver.getMatchPatterns(), line)) { + String funcName = line.replaceAll("^[ \\t]+", ""); + return funcName.substring(0, + Math.min(funcName.length(), 80)).trim(); + } + } + } + return null; + } + + private boolean matchesAny(List patterns, String text) { + if (patterns != null) { + for (Pattern p : patterns) { + if (p.matcher(text).find()) { + return true; + } + } + } + return false; + } + + private DiffDriver getDiffDriver(DiffEntry entry) { + Attribute diffAttr = entry.getDiffAttribute(); + if (diffAttr != null) { + try { + return DiffDriver.valueOf(diffAttr.getValue()); + } catch (IllegalArgumentException e) { + return null; + } + } + return null; + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/PatchIdDiffFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/PatchIdDiffFormatter.java index 4343642f9a..b401bbe73d 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/PatchIdDiffFormatter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/PatchIdDiffFormatter.java @@ -44,8 +44,8 @@ public class PatchIdDiffFormatter extends DiffFormatter { } @Override - protected void writeHunkHeader(int aStartLine, int aEndLine, - int bStartLine, int bEndLine) throws IOException { + protected void writeHunkHeader(int aStartLine, int aEndLine, int bStartLine, + int bEndLine, String funcName) throws IOException { // The hunk header is not taken into account for patch id calculation } -- cgit v1.2.3 From 469928898db10d4b19bd34658d3b2f93f12952b3 Mon Sep 17 00:00:00 2001 From: Jacek Centkowski Date: Thu, 31 Oct 2024 18:30:02 +0100 Subject: Add numberOfObjectsSinceBitmap to RepoStatistics Introduce a numberOfObjectsSinceBitmap that contains the number of objects stored in pack files and as loose objects created since the latest bitmap generation. Note that the existing GcNumberOfPackFilesAfterBitmapStatisticsTest.java was renamed to GcSinceBitmapStatisticsTest.java and extended to cover also this statistic. Change-Id: I8ae1db142ddfcd42a5a1d6da01bc67f695562e0e --- ...NumberOfPackFilesSinceBitmapStatisticsTest.java | 97 ------------ .../storage/file/GcSinceBitmapStatisticsTest.java | 167 +++++++++++++++++++++ .../org/eclipse/jgit/internal/storage/file/GC.java | 18 ++- 3 files changed, 184 insertions(+), 98 deletions(-) delete mode 100644 org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcNumberOfPackFilesSinceBitmapStatisticsTest.java create mode 100644 org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcSinceBitmapStatisticsTest.java (limited to 'org.eclipse.jgit.test/tst/org/eclipse/jgit') diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcNumberOfPackFilesSinceBitmapStatisticsTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcNumberOfPackFilesSinceBitmapStatisticsTest.java deleted file mode 100644 index fa13bb57c8..0000000000 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcNumberOfPackFilesSinceBitmapStatisticsTest.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2024 Jacek Centkowski and others. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Distribution License v. 1.0 which is available at - * https://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -package org.eclipse.jgit.internal.storage.file; - -import static org.junit.Assert.assertEquals; - -import java.io.IOException; -import java.nio.file.Files; -import java.util.stream.StreamSupport; - -import org.eclipse.jgit.lib.PersonIdent; -import org.eclipse.jgit.revwalk.RevCommit; -import org.junit.Test; - -public class GcNumberOfPackFilesSinceBitmapStatisticsTest extends GcTestCase { - @Test - public void testShouldReportZeroObjectsForInitializedRepo() - throws IOException { - assertEquals(0L, gc.getStatistics().numberOfPackFilesSinceBitmap); - } - - @Test - public void testShouldReportAllPackFilesWhenNoGcWasPerformed() - throws Exception { - tr.packAndPrune(); - long result = gc.getStatistics().numberOfPackFilesSinceBitmap; - - assertEquals(repo.getObjectDatabase().getPacks().size(), result); - } - - @Test - public void testShouldReportNoObjectsDirectlyAfterGc() throws Exception { - // given - addCommit(null); - gc.gc().get(); - assertEquals(1L, repositoryBitmapFiles()); - assertEquals(0L, gc.getStatistics().numberOfPackFilesSinceBitmap); - } - - @Test - public void testShouldReportNewObjectsSinceGcWhenRepositoryProgresses() - throws Exception { - // commit & gc - RevCommit parent = addCommit(null); - gc.gc().get(); - assertEquals(1L, repositoryBitmapFiles()); - - // progress & pack - addCommit(parent); - tr.packAndPrune(); - - assertEquals(1L, gc.getStatistics().numberOfPackFilesSinceBitmap); - } - - @Test - public void testShouldReportNewObjectsFromTheLatestBitmapWhenRepositoryProgresses() - throws Exception { - // commit & gc - RevCommit parent = addCommit(null); - gc.gc().get(); - assertEquals(1L, repositoryBitmapFiles()); - - // progress & gc - parent = addCommit(parent); - gc.gc().get(); - assertEquals(2L, repositoryBitmapFiles()); - - // progress & pack - addCommit(parent); - tr.packAndPrune(); - - assertEquals(1L, gc.getStatistics().numberOfPackFilesSinceBitmap); - } - - private RevCommit addCommit(RevCommit parent) throws Exception { - return tr.branch("master").commit() - .author(new PersonIdent("repo-metrics", "repo@metrics.com")) - .parent(parent).create(); - } - - private long repositoryBitmapFiles() throws IOException { - return StreamSupport - .stream(Files - .newDirectoryStream(repo.getObjectDatabase() - .getPackDirectory().toPath(), "pack-*.bitmap") - .spliterator(), false) - .count(); - } -} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcSinceBitmapStatisticsTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcSinceBitmapStatisticsTest.java new file mode 100644 index 0000000000..3cd766c4e9 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcSinceBitmapStatisticsTest.java @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2024 Jacek Centkowski and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.internal.storage.file; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.nio.file.Files; +import java.util.Collection; +import java.util.stream.StreamSupport; + +import org.eclipse.jgit.internal.storage.file.GC.RepoStatistics; +import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.revwalk.RevCommit; +import org.junit.Test; + +public class GcSinceBitmapStatisticsTest extends GcTestCase { + @Test + public void testShouldReportZeroPacksAndObjectsForInitializedRepo() + throws IOException { + RepoStatistics s = gc.getStatistics(); + assertEquals(0L, s.numberOfPackFilesSinceBitmap); + assertEquals(0L, s.numberOfObjectsSinceBitmap); + } + + @Test + public void testShouldReportAllPackFilesWhenNoGcWasPerformed() + throws Exception { + tr.packAndPrune(); + long result = gc.getStatistics().numberOfPackFilesSinceBitmap; + + assertEquals(repo.getObjectDatabase().getPacks().size(), result); + } + + @Test + public void testShouldReportAllObjectsWhenNoGcWasPerformed() + throws Exception { + tr.packAndPrune(); + + assertEquals( + getNumberOfObjectsInPacks(repo.getObjectDatabase().getPacks()), + gc.getStatistics().numberOfObjectsSinceBitmap); + } + + @Test + public void testShouldReportNoPacksDirectlyAfterGc() throws Exception { + // given + addCommit(null); + gc.gc().get(); + assertEquals(1L, repositoryBitmapFiles()); + assertEquals(0L, gc.getStatistics().numberOfPackFilesSinceBitmap); + } + + @Test + public void testShouldReportNoObjectsDirectlyAfterGc() throws Exception { + // given + addCommit(null); + assertEquals(2L, gc.getStatistics().numberOfObjectsSinceBitmap); + + gc.gc().get(); + assertEquals(0L, gc.getStatistics().numberOfObjectsSinceBitmap); + } + + @Test + public void testShouldReportNewPacksSinceGcWhenRepositoryProgresses() + throws Exception { + // commit & gc + RevCommit parent = addCommit(null); + gc.gc().get(); + assertEquals(1L, repositoryBitmapFiles()); + + // progress & pack + addCommit(parent); + tr.packAndPrune(); + + assertEquals(1L, gc.getStatistics().numberOfPackFilesSinceBitmap); + } + + @Test + public void testShouldReportNewObjectsSinceGcWhenRepositoryProgresses() + throws Exception { + // commit & gc + RevCommit parent = addCommit(null); + gc.gc().get(); + assertEquals(0L, gc.getStatistics().numberOfObjectsSinceBitmap); + + // progress & pack + addCommit(parent); + assertEquals(1L, gc.getStatistics().numberOfObjectsSinceBitmap); + + tr.packAndPrune(); + assertEquals(3L, gc.getStatistics().numberOfObjectsSinceBitmap); + } + + @Test + public void testShouldReportNewPacksFromTheLatestBitmapWhenRepositoryProgresses() + throws Exception { + // commit & gc + RevCommit parent = addCommit(null); + gc.gc().get(); + assertEquals(1L, repositoryBitmapFiles()); + + // progress & gc + parent = addCommit(parent); + gc.gc().get(); + assertEquals(2L, repositoryBitmapFiles()); + + // progress & pack + addCommit(parent); + tr.packAndPrune(); + + assertEquals(1L, gc.getStatistics().numberOfPackFilesSinceBitmap); + } + + @Test + public void testShouldReportNewObjectsFromTheLatestBitmapWhenRepositoryProgresses() + throws Exception { + // commit & gc + RevCommit parent = addCommit(null); + gc.gc().get(); + + // progress & gc + parent = addCommit(parent); + gc.gc().get(); + assertEquals(0L, gc.getStatistics().numberOfObjectsSinceBitmap); + + // progress & pack + addCommit(parent); + assertEquals(1L, gc.getStatistics().numberOfObjectsSinceBitmap); + + tr.packAndPrune(); + assertEquals(4L, gc.getStatistics().numberOfObjectsSinceBitmap); + } + + private RevCommit addCommit(RevCommit parent) throws Exception { + return tr.branch("master").commit() + .author(new PersonIdent("repo-metrics", "repo@metrics.com")) + .parent(parent).create(); + } + + private long repositoryBitmapFiles() throws IOException { + return StreamSupport + .stream(Files + .newDirectoryStream(repo.getObjectDatabase() + .getPackDirectory().toPath(), "pack-*.bitmap") + .spliterator(), false) + .count(); + } + + private long getNumberOfObjectsInPacks(Collection packs) { + return packs.stream().mapToLong(pack -> { + try { + return pack.getObjectCount(); + } catch (IOException e) { + throw new RuntimeException(e); + } + }).sum(); + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java index 9494057a60..b33afed131 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java @@ -1514,6 +1514,12 @@ public class GC { */ public long numberOfPackFilesSinceBitmap; + /** + * The number of objects stored in pack files and as loose object + * created after the last bitmap generation. + */ + public long numberOfObjectsSinceBitmap; + /** * The number of objects stored as loose objects. */ @@ -1551,6 +1557,8 @@ public class GC { b.append(", numberOfPackFiles=").append(numberOfPackFiles); //$NON-NLS-1$ b.append(", numberOfPackFilesSinceBitmap=") //$NON-NLS-1$ .append(numberOfPackFilesSinceBitmap); + b.append(", numberOfObjectsSinceBitmap=") //$NON-NLS-1$ + .append(numberOfObjectsSinceBitmap); b.append(", numberOfLooseObjects=").append(numberOfLooseObjects); //$NON-NLS-1$ b.append(", numberOfLooseRefs=").append(numberOfLooseRefs); //$NON-NLS-1$ b.append(", numberOfPackedRefs=").append(numberOfPackedRefs); //$NON-NLS-1$ @@ -1571,14 +1579,19 @@ public class GC { public RepoStatistics getStatistics() throws IOException { RepoStatistics ret = new RepoStatistics(); Collection packs = repo.getObjectDatabase().getPacks(); + long latestBitmapTime = Long.MIN_VALUE; for (Pack p : packs) { - ret.numberOfPackedObjects += p.getIndex().getObjectCount(); + long packedObjects = p.getIndex().getObjectCount(); + ret.numberOfPackedObjects += packedObjects; ret.numberOfPackFiles++; ret.sizeOfPackedObjects += p.getPackFile().length(); if (p.getBitmapIndex() != null) { ret.numberOfBitmaps += p.getBitmapIndex().getBitmapCount(); + latestBitmapTime = p.getFileSnapshot().lastModifiedInstant() + .toEpochMilli(); } else { ret.numberOfPackFilesSinceBitmap++; + ret.numberOfObjectsSinceBitmap += packedObjects; } } File objDir = repo.getObjectsDirectory(); @@ -1595,6 +1608,9 @@ public class GC { continue; ret.numberOfLooseObjects++; ret.sizeOfLooseObjects += f.length(); + if (f.lastModified() > latestBitmapTime) { + ret.numberOfObjectsSinceBitmap ++; + } } } } -- cgit v1.2.3