From bd06ff3a97472151de2180ca5f2ec8ffe41d99f1 Mon Sep 17 00:00:00 2001
From: Shinpei Hayashi
Date: Sun, 29 Mar 2026 01:07:42 +0900
Subject: [PATCH 1/6] refactor: rename classes
---
.../titech/c/se/stein/app/blob/Historage.java | 2 +-
...HistorageViaJDT.java => HistorageJdt.java} | 2 +-
.../titech/c/se/stein/app/blob/Tokenize.java | 2 +-
.../{TokenizeViaJDT.java => TokenizeJdt.java} | 4 ++--
...eViaJDTTest.java => HistorageJdtTest.java} | 24 +++++++++----------
...zeViaJDTTest.java => TokenizeJdtTest.java} | 14 +++++------
.../c/se/stein/app/commit/NoteCommitTest.java | 10 ++++----
.../core/cache/PersistentEntryCacheTest.java | 6 ++---
.../se/stein/rewriter/BlobTranslatorTest.java | 10 ++++----
.../stein/rewriter/CommitTranslatorTest.java | 6 ++---
.../c/se/stein/testing/MemoryProfile.java | 4 ++--
.../c/se/stein/testing/RewriteBenchmark.java | 10 ++++----
12 files changed, 47 insertions(+), 47 deletions(-)
rename src/main/java/jp/ac/titech/c/se/stein/app/blob/{HistorageViaJDT.java => HistorageJdt.java} (99%)
rename src/main/java/jp/ac/titech/c/se/stein/app/blob/{TokenizeViaJDT.java => TokenizeJdt.java} (95%)
rename src/test/java/jp/ac/titech/c/se/stein/app/blob/{HistorageViaJDTTest.java => HistorageJdtTest.java} (91%)
rename src/test/java/jp/ac/titech/c/se/stein/app/blob/{TokenizeViaJDTTest.java => TokenizeJdtTest.java} (75%)
diff --git a/src/main/java/jp/ac/titech/c/se/stein/app/blob/Historage.java b/src/main/java/jp/ac/titech/c/se/stein/app/blob/Historage.java
index d22b497..ddbfc7e 100644
--- a/src/main/java/jp/ac/titech/c/se/stein/app/blob/Historage.java
+++ b/src/main/java/jp/ac/titech/c/se/stein/app/blob/Historage.java
@@ -29,7 +29,7 @@
/**
* A Historage generator using universal-ctags.
* Splits source files into finer-grained modules (one file per language object)
- * based on ctags output. For Java-specific splitting via JDT, see {@link HistorageViaJDT}.
+ * based on ctags output. For Java-specific splitting via JDT, see {@link HistorageJdt}.
*
* Requires the {@code ctags} command to be available on the system.
*/
diff --git a/src/main/java/jp/ac/titech/c/se/stein/app/blob/HistorageViaJDT.java b/src/main/java/jp/ac/titech/c/se/stein/app/blob/HistorageJdt.java
similarity index 99%
rename from src/main/java/jp/ac/titech/c/se/stein/app/blob/HistorageViaJDT.java
rename to src/main/java/jp/ac/titech/c/se/stein/app/blob/HistorageJdt.java
index 889a622..6a9206b 100644
--- a/src/main/java/jp/ac/titech/c/se/stein/app/blob/HistorageViaJDT.java
+++ b/src/main/java/jp/ac/titech/c/se/stein/app/blob/HistorageJdt.java
@@ -36,7 +36,7 @@
@Slf4j
@ToString
@Command(name = "@historage-jdt", description = "Generate finer-grained Java modules via JDT")
-public class HistorageViaJDT implements BlobTranslator {
+public class HistorageJdt implements BlobTranslator {
public static final NameFilter JAVA = new NameFilter(true, "*.java");
public static final Gson GSON = new Gson();
diff --git a/src/main/java/jp/ac/titech/c/se/stein/app/blob/Tokenize.java b/src/main/java/jp/ac/titech/c/se/stein/app/blob/Tokenize.java
index 007ff0a..e783899 100644
--- a/src/main/java/jp/ac/titech/c/se/stein/app/blob/Tokenize.java
+++ b/src/main/java/jp/ac/titech/c/se/stein/app/blob/Tokenize.java
@@ -17,7 +17,7 @@
* The inverse operation is {@link Untokenize}.
*
* Tokenization is language-agnostic, splitting on whitespace, word characters, and symbols.
- * For Java-aware tokenization, see {@link TokenizeViaJDT}.
+ * For Java-aware tokenization, see {@link TokenizeJdt}.
*/
@ToString
@Command(name = "@tokenize", description = "Encode source files to linetoken format")
diff --git a/src/main/java/jp/ac/titech/c/se/stein/app/blob/TokenizeViaJDT.java b/src/main/java/jp/ac/titech/c/se/stein/app/blob/TokenizeJdt.java
similarity index 95%
rename from src/main/java/jp/ac/titech/c/se/stein/app/blob/TokenizeViaJDT.java
rename to src/main/java/jp/ac/titech/c/se/stein/app/blob/TokenizeJdt.java
index 2f68715..060476b 100644
--- a/src/main/java/jp/ac/titech/c/se/stein/app/blob/TokenizeViaJDT.java
+++ b/src/main/java/jp/ac/titech/c/se/stein/app/blob/TokenizeJdt.java
@@ -23,10 +23,10 @@
@Slf4j
@ToString
@Command(name = "@tokenize-jdt", description = "Encode Java source files to linetoken format via JDT")
-public class TokenizeViaJDT implements BlobTranslator {
+public class TokenizeJdt implements BlobTranslator {
@Override
public AnyHotEntry rewriteBlobEntry(final BlobEntry entry, final Context c) {
- if (!HistorageViaJDT.JAVA.accept(entry)) {
+ if (!HistorageJdt.JAVA.accept(entry)) {
return entry;
}
final String text = SourceText.of(entry.getBlob()).getContent();
diff --git a/src/test/java/jp/ac/titech/c/se/stein/app/blob/HistorageViaJDTTest.java b/src/test/java/jp/ac/titech/c/se/stein/app/blob/HistorageJdtTest.java
similarity index 91%
rename from src/test/java/jp/ac/titech/c/se/stein/app/blob/HistorageViaJDTTest.java
rename to src/test/java/jp/ac/titech/c/se/stein/app/blob/HistorageJdtTest.java
index b54eb68..05a5dcd 100644
--- a/src/test/java/jp/ac/titech/c/se/stein/app/blob/HistorageViaJDTTest.java
+++ b/src/test/java/jp/ac/titech/c/se/stein/app/blob/HistorageJdtTest.java
@@ -1,6 +1,6 @@
package jp.ac.titech.c.se.stein.app.blob;
-import jp.ac.titech.c.se.stein.app.blob.HistorageViaJDT.Module;
+import jp.ac.titech.c.se.stein.app.blob.HistorageJdt.Module;
import jp.ac.titech.c.se.stein.core.Context;
import jp.ac.titech.c.se.stein.core.SourceText;
import jp.ac.titech.c.se.stein.entry.AnyHotEntry;
@@ -23,18 +23,18 @@
import static org.junit.jupiter.api.Assertions.*;
-public class HistorageViaJDTTest {
+public class HistorageJdtTest {
static String sampleSource;
static RepositoryAccess source, result;
@BeforeAll
static void setUp() throws IOException {
- try (InputStream is = HistorageViaJDTTest.class.getResourceAsStream("/sample/Hello.java.v3")) {
+ try (InputStream is = HistorageJdtTest.class.getResourceAsStream("/sample/Hello.java.v3")) {
sampleSource = new String(is.readAllBytes(), StandardCharsets.UTF_8);
}
source = TestRepo.createSample();
- result = TestRepo.rewrite(source,new HistorageViaJDT());
+ result = TestRepo.rewrite(source,new HistorageJdt());
}
@AfterAll
@@ -44,10 +44,10 @@ static void tearDown() {
}
List generateModules() {
- return generateModules(new HistorageViaJDT());
+ return generateModules(new HistorageJdt());
}
- List generateModules(HistorageViaJDT historage) {
+ List generateModules(HistorageJdt historage) {
SourceText text = SourceText.ofNormalized(sampleSource.getBytes(StandardCharsets.UTF_8));
return historage.new ModuleGenerator("Hello.java", text).generate();
}
@@ -125,7 +125,7 @@ public void testModuleContent() {
@Test
public void testExcludeClasses() {
- HistorageViaJDT historage = new HistorageViaJDT();
+ HistorageJdt historage = new HistorageJdt();
historage.requiresClasses = false;
assertTrue(generateModules(historage).stream()
.noneMatch(m -> m.getFilename().endsWith(".cjava")));
@@ -133,7 +133,7 @@ public void testExcludeClasses() {
@Test
public void testExcludeMethods() {
- HistorageViaJDT historage = new HistorageViaJDT();
+ HistorageJdt historage = new HistorageJdt();
historage.requiresMethods = false;
assertTrue(generateModules(historage).stream()
.noneMatch(m -> m.getFilename().endsWith(".mjava")));
@@ -141,7 +141,7 @@ public void testExcludeMethods() {
@Test
public void testExcludeFields() {
- HistorageViaJDT historage = new HistorageViaJDT();
+ HistorageJdt historage = new HistorageJdt();
historage.requiresFields = false;
assertTrue(generateModules(historage).stream()
.noneMatch(m -> m.getFilename().endsWith(".fjava")));
@@ -149,7 +149,7 @@ public void testExcludeFields() {
@Test
public void testDigestParameters() {
- HistorageViaJDT historage = new HistorageViaJDT();
+ HistorageJdt historage = new HistorageJdt();
historage.digestParameters = true;
List modules = generateModules(historage);
@@ -166,7 +166,7 @@ public void testDigestParameters() {
@Test
public void testNonJavaFilePassedThrough() {
BlobEntry entry = HotEntry.ofBlob("README.md", "# Hello");
- HistorageViaJDT historage = new HistorageViaJDT();
+ HistorageJdt historage = new HistorageJdt();
AnyHotEntry result = historage.rewriteBlobEntry(entry, Context.init());
assertEquals(1, result.size());
assertSame(entry, result.stream().findFirst().orElseThrow());
@@ -174,7 +174,7 @@ public void testNonJavaFilePassedThrough() {
@Test
public void testRequiresOriginals() {
- HistorageViaJDT historage = new HistorageViaJDT();
+ HistorageJdt historage = new HistorageJdt();
historage.requiresOriginals = false;
BlobEntry entry = HotEntry.ofBlob("Hello.java", sampleSource);
AnyHotEntry result = historage.rewriteBlobEntry(entry, Context.init());
diff --git a/src/test/java/jp/ac/titech/c/se/stein/app/blob/TokenizeViaJDTTest.java b/src/test/java/jp/ac/titech/c/se/stein/app/blob/TokenizeJdtTest.java
similarity index 75%
rename from src/test/java/jp/ac/titech/c/se/stein/app/blob/TokenizeViaJDTTest.java
rename to src/test/java/jp/ac/titech/c/se/stein/app/blob/TokenizeJdtTest.java
index af8cf5b..abdfdef 100644
--- a/src/test/java/jp/ac/titech/c/se/stein/app/blob/TokenizeViaJDTTest.java
+++ b/src/test/java/jp/ac/titech/c/se/stein/app/blob/TokenizeJdtTest.java
@@ -9,33 +9,33 @@
import static jp.ac.titech.c.se.stein.app.blob.TokenizeTest.tokens;
import static org.junit.jupiter.api.Assertions.*;
-public class TokenizeViaJDTTest {
+public class TokenizeJdtTest {
@Test
public void testEncode() {
- assertEquals("", TokenizeViaJDT.encode(""));
+ assertEquals("", TokenizeJdt.encode(""));
assertEquals(tokens("int", " ", "x", " ", "=", " ", "1", ";"),
- TokenizeViaJDT.encode("int x = 1;"));
+ TokenizeJdt.encode("int x = 1;"));
}
@Test
public void testEncodePreservesComments() {
// JDT scanner includes trailing newline in line comment token
assertEquals(tokens("// comment\r", "int", " ", "x", ";"),
- TokenizeViaJDT.encode("// comment\nint x;"));
+ TokenizeJdt.encode("// comment\nint x;"));
}
@Test
public void testEncodePreservesStringLiteral() {
assertEquals(tokens("String", " ", "s", " ", "=", " ", "\"hello\"", ";"),
- TokenizeViaJDT.encode("String s = \"hello\";"));
+ TokenizeJdt.encode("String s = \"hello\";"));
}
@Test
public void testEncodeMultiline() {
assertEquals(tokens("class", " ", "A", " ", "{", "\r", "}"),
- TokenizeViaJDT.encode("class A {\n}"));
+ TokenizeJdt.encode("class A {\n}"));
}
@Test
@@ -47,6 +47,6 @@ public void testRoundTrip() throws IOException {
}
private void assertRoundTrip(String source) {
- assertEquals(source, Untokenize.decode(TokenizeViaJDT.encode(source)));
+ assertEquals(source, Untokenize.decode(TokenizeJdt.encode(source)));
}
}
diff --git a/src/test/java/jp/ac/titech/c/se/stein/app/commit/NoteCommitTest.java b/src/test/java/jp/ac/titech/c/se/stein/app/commit/NoteCommitTest.java
index 8ee339f..8475213 100644
--- a/src/test/java/jp/ac/titech/c/se/stein/app/commit/NoteCommitTest.java
+++ b/src/test/java/jp/ac/titech/c/se/stein/app/commit/NoteCommitTest.java
@@ -1,7 +1,7 @@
package jp.ac.titech.c.se.stein.app.commit;
-import jp.ac.titech.c.se.stein.app.blob.HistorageViaJDT;
-import jp.ac.titech.c.se.stein.app.blob.TokenizeViaJDT;
+import jp.ac.titech.c.se.stein.app.blob.HistorageJdt;
+import jp.ac.titech.c.se.stein.app.blob.TokenizeJdt;
import jp.ac.titech.c.se.stein.core.RepositoryAccess;
import jp.ac.titech.c.se.stein.testing.TestRepo;
import org.eclipse.jgit.revwalk.RevCommit;
@@ -50,7 +50,7 @@ public void testSingleTransform() {
// Tokenize → NoteCommit: notes contain original commit IDs
final List sourceCommits = source.collectCommits("refs/heads/main");
- try (RepositoryAccess tokenized = TestRepo.rewrite(source,new TokenizeViaJDT());
+ try (RepositoryAccess tokenized = TestRepo.rewrite(source,new TokenizeJdt());
RepositoryAccess noted = TestRepo.rewrite(tokenized,new NoteCommit())) {
final List commits = noted.collectCommits("refs/heads/main");
@@ -70,8 +70,8 @@ public void testDoubleTransform() {
// Historage → Tokenize → NoteCommit: notes should still trace back to original
final List sourceCommits = source.collectCommits("refs/heads/main");
- try (RepositoryAccess step1 = TestRepo.rewrite(source,new HistorageViaJDT());
- RepositoryAccess step2 = TestRepo.rewrite(step1,new TokenizeViaJDT());
+ try (RepositoryAccess step1 = TestRepo.rewrite(source,new HistorageJdt());
+ RepositoryAccess step2 = TestRepo.rewrite(step1,new TokenizeJdt());
RepositoryAccess noted = TestRepo.rewrite(step2,new NoteCommit())) {
final List commits = noted.collectCommits("refs/heads/main");
diff --git a/src/test/java/jp/ac/titech/c/se/stein/core/cache/PersistentEntryCacheTest.java b/src/test/java/jp/ac/titech/c/se/stein/core/cache/PersistentEntryCacheTest.java
index 7d3ecf7..c921c17 100644
--- a/src/test/java/jp/ac/titech/c/se/stein/core/cache/PersistentEntryCacheTest.java
+++ b/src/test/java/jp/ac/titech/c/se/stein/core/cache/PersistentEntryCacheTest.java
@@ -5,7 +5,7 @@
import jp.ac.titech.c.se.stein.Application;
import jp.ac.titech.c.se.stein.app.Identity;
-import jp.ac.titech.c.se.stein.app.blob.HistorageViaJDT;
+import jp.ac.titech.c.se.stein.app.blob.HistorageJdt;
import jp.ac.titech.c.se.stein.rewriter.BlobTranslator;
import jp.ac.titech.c.se.stein.rewriter.RepositoryRewriter;
import jp.ac.titech.c.se.stein.testing.TestRepo;
@@ -85,11 +85,11 @@ public void testCacheMatchesNonCachedResult() {
@Test
public void testCacheWithHistorage() {
try (RepositoryAccess target = TestRepo.create(true)) {
- rewriteWithCache(new HistorageViaJDT().toRewriter(), target.repo);
+ rewriteWithCache(new HistorageJdt().toRewriter(), target.repo);
final List firstRun = target.collectCommits("refs/heads/main");
assertFalse(firstRun.isEmpty());
- rewriteWithCache(new HistorageViaJDT().toRewriter(), target.repo);
+ rewriteWithCache(new HistorageJdt().toRewriter(), target.repo);
final List secondRun = target.collectCommits("refs/heads/main");
assertEquals(firstRun.size(), secondRun.size());
diff --git a/src/test/java/jp/ac/titech/c/se/stein/rewriter/BlobTranslatorTest.java b/src/test/java/jp/ac/titech/c/se/stein/rewriter/BlobTranslatorTest.java
index bac1468..cc9ceb2 100644
--- a/src/test/java/jp/ac/titech/c/se/stein/rewriter/BlobTranslatorTest.java
+++ b/src/test/java/jp/ac/titech/c/se/stein/rewriter/BlobTranslatorTest.java
@@ -1,7 +1,7 @@
package jp.ac.titech.c.se.stein.rewriter;
-import jp.ac.titech.c.se.stein.app.blob.HistorageViaJDT;
-import jp.ac.titech.c.se.stein.app.blob.TokenizeViaJDT;
+import jp.ac.titech.c.se.stein.app.blob.HistorageJdt;
+import jp.ac.titech.c.se.stein.app.blob.TokenizeJdt;
import jp.ac.titech.c.se.stein.core.Context;
import jp.ac.titech.c.se.stein.entry.AnyHotEntry;
import jp.ac.titech.c.se.stein.entry.Entry;
@@ -88,11 +88,11 @@ public void testSplitThenTransform() {
@Test
public void testFinerGit() throws IOException {
try (RepositoryAccess source = TestRepo.createSample()) {
- final BlobTranslator composite = BlobTranslator.composite(new HistorageViaJDT(), new TokenizeViaJDT());
+ final BlobTranslator composite = BlobTranslator.composite(new HistorageJdt(), new TokenizeJdt());
try (RepositoryAccess compositeResult = TestRepo.rewrite(source, composite);
- RepositoryAccess step1 = TestRepo.rewrite(source, new HistorageViaJDT());
- RepositoryAccess sequentialResult = TestRepo.rewrite(step1, new TokenizeViaJDT())) {
+ RepositoryAccess step1 = TestRepo.rewrite(source, new HistorageJdt());
+ RepositoryAccess sequentialResult = TestRepo.rewrite(step1, new TokenizeJdt())) {
final RevCommit compositeHead = compositeResult.getHead("refs/heads/main");
final RevCommit sequentialHead = sequentialResult.getHead("refs/heads/main");
diff --git a/src/test/java/jp/ac/titech/c/se/stein/rewriter/CommitTranslatorTest.java b/src/test/java/jp/ac/titech/c/se/stein/rewriter/CommitTranslatorTest.java
index a696d39..9460296 100644
--- a/src/test/java/jp/ac/titech/c/se/stein/rewriter/CommitTranslatorTest.java
+++ b/src/test/java/jp/ac/titech/c/se/stein/rewriter/CommitTranslatorTest.java
@@ -1,6 +1,6 @@
package jp.ac.titech.c.se.stein.rewriter;
-import jp.ac.titech.c.se.stein.app.blob.TokenizeViaJDT;
+import jp.ac.titech.c.se.stein.app.blob.TokenizeJdt;
import jp.ac.titech.c.se.stein.app.commit.NoteCommit;
import jp.ac.titech.c.se.stein.core.Context;
import jp.ac.titech.c.se.stein.core.RepositoryAccess;
@@ -125,11 +125,11 @@ public void testCompositeWithBlobOnRepo() throws IOException {
final List sourceCommits = source.collectCommits("refs/heads/main");
final CommitTranslator composite = CommitTranslator.composite(
- CommitTranslator.fromBlob(new TokenizeViaJDT()),
+ CommitTranslator.fromBlob(new TokenizeJdt()),
new NoteCommit());
try (RepositoryAccess compositeResult = TestRepo.rewrite(source, composite);
- RepositoryAccess step1 = TestRepo.rewrite(source, new TokenizeViaJDT());
+ RepositoryAccess step1 = TestRepo.rewrite(source, new TokenizeJdt());
RepositoryAccess sequentialResult = TestRepo.rewrite(step1, new NoteCommit())) {
final List compositeCommits = compositeResult.collectCommits("refs/heads/main");
diff --git a/src/test/java/jp/ac/titech/c/se/stein/testing/MemoryProfile.java b/src/test/java/jp/ac/titech/c/se/stein/testing/MemoryProfile.java
index 2eac5bf..fab8755 100644
--- a/src/test/java/jp/ac/titech/c/se/stein/testing/MemoryProfile.java
+++ b/src/test/java/jp/ac/titech/c/se/stein/testing/MemoryProfile.java
@@ -2,7 +2,7 @@
import jp.ac.titech.c.se.stein.Application;
import jp.ac.titech.c.se.stein.app.Identity;
-import jp.ac.titech.c.se.stein.app.blob.HistorageViaJDT;
+import jp.ac.titech.c.se.stein.app.blob.HistorageJdt;
import jp.ac.titech.c.se.stein.core.Context;
import jp.ac.titech.c.se.stein.rewriter.RepositoryRewriter;
import jp.ac.titech.c.se.stein.util.TemporaryFile;
@@ -42,7 +42,7 @@ public static void main(String[] args) throws Exception {
final FileRepository targetRepo = createRepository(tmp.getPath().toFile());
final RepositoryRewriter rewriter = switch (command) {
- case "historage" -> new HistorageViaJDT().toRewriter();
+ case "historage" -> new HistorageJdt().toRewriter();
default -> new Identity();
};
rewriter.setConfig(new Application.Config());
diff --git a/src/test/java/jp/ac/titech/c/se/stein/testing/RewriteBenchmark.java b/src/test/java/jp/ac/titech/c/se/stein/testing/RewriteBenchmark.java
index ef43a58..ec4d5e8 100644
--- a/src/test/java/jp/ac/titech/c/se/stein/testing/RewriteBenchmark.java
+++ b/src/test/java/jp/ac/titech/c/se/stein/testing/RewriteBenchmark.java
@@ -5,8 +5,8 @@
import com.google.gson.JsonObject;
import jp.ac.titech.c.se.stein.Application;
import jp.ac.titech.c.se.stein.app.Identity;
-import jp.ac.titech.c.se.stein.app.blob.HistorageViaJDT;
-import jp.ac.titech.c.se.stein.app.blob.TokenizeViaJDT;
+import jp.ac.titech.c.se.stein.app.blob.HistorageJdt;
+import jp.ac.titech.c.se.stein.app.blob.TokenizeJdt;
import jp.ac.titech.c.se.stein.core.Context;
import jp.ac.titech.c.se.stein.rewriter.BlobTranslator;
import jp.ac.titech.c.se.stein.rewriter.RepositoryRewriter;
@@ -53,10 +53,10 @@ public static void main(String[] args) throws Exception {
final List results = new ArrayList<>();
results.add(benchmark("identity", sourceDir, Identity::new, alternates, cache));
- results.add(benchmark("tokenize-jdt", sourceDir, () -> new TokenizeViaJDT().toRewriter(), alternates, cache));
- results.add(benchmark("historage-jdt", sourceDir, () -> new HistorageViaJDT().toRewriter(), alternates, cache));
+ results.add(benchmark("tokenize-jdt", sourceDir, () -> new TokenizeJdt().toRewriter(), alternates, cache));
+ results.add(benchmark("historage-jdt", sourceDir, () -> new HistorageJdt().toRewriter(), alternates, cache));
results.add(benchmark("historage+tokenize", sourceDir,
- () -> BlobTranslator.composite(new HistorageViaJDT(), new TokenizeViaJDT()).toRewriter(), alternates, cache));
+ () -> BlobTranslator.composite(new HistorageJdt(), new TokenizeJdt()).toRewriter(), alternates, cache));
// summary
System.out.println();
From af9872f81fbac781fcacc74cc6c9ccbe3a9f8f7e Mon Sep 17 00:00:00 2001
From: Shinpei Hayashi
Date: Sun, 29 Mar 2026 09:07:58 +0900
Subject: [PATCH 2/6] ensure killing subprocess
---
.../java/jp/ac/titech/c/se/stein/util/ProcessRunner.java | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/main/java/jp/ac/titech/c/se/stein/util/ProcessRunner.java b/src/main/java/jp/ac/titech/c/se/stein/util/ProcessRunner.java
index 15f933e..c59a0a9 100644
--- a/src/main/java/jp/ac/titech/c/se/stein/util/ProcessRunner.java
+++ b/src/main/java/jp/ac/titech/c/se/stein/util/ProcessRunner.java
@@ -18,8 +18,12 @@ public static boolean isAvailable(String command) {
try {
final Process p = new ProcessBuilder(command, "--version")
.redirectErrorStream(true).start();
- p.getInputStream().readAllBytes();
- return p.waitFor() == 0;
+ try {
+ p.getInputStream().readAllBytes();
+ return p.waitFor() == 0;
+ } finally {
+ p.destroyForcibly();
+ }
} catch (Exception e) {
return false;
}
From c22d7e4a395e85de941c4b9092d563d9cee88529 Mon Sep 17 00:00:00 2001
From: Shinpei Hayashi
Date: Sun, 29 Mar 2026 09:08:54 +0900
Subject: [PATCH 3/6] error log already redirected
---
src/main/java/jp/ac/titech/c/se/stein/util/ProcessRunner.java | 3 ---
1 file changed, 3 deletions(-)
diff --git a/src/main/java/jp/ac/titech/c/se/stein/util/ProcessRunner.java b/src/main/java/jp/ac/titech/c/se/stein/util/ProcessRunner.java
index c59a0a9..d591ecc 100644
--- a/src/main/java/jp/ac/titech/c/se/stein/util/ProcessRunner.java
+++ b/src/main/java/jp/ac/titech/c/se/stein/util/ProcessRunner.java
@@ -83,9 +83,6 @@ public byte[] getResult() {
@Override
public void close() throws IOException {
- try (final BufferedReader err = new BufferedReader(new InputStreamReader(proc.getErrorStream()))) {
- err.lines().forEach(line -> log.warn("stderr: {} {}", line, c));
- }
if (reader != null) {
reader.close();
}
From 3906b9786c2729908a17eef52844d22055e25e00 Mon Sep 17 00:00:00 2001
From: Shinpei Hayashi
Date: Sun, 29 Mar 2026 09:09:19 +0900
Subject: [PATCH 4/6] wait subprocess
---
.../java/jp/ac/titech/c/se/stein/util/ProcessRunner.java | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/src/main/java/jp/ac/titech/c/se/stein/util/ProcessRunner.java b/src/main/java/jp/ac/titech/c/se/stein/util/ProcessRunner.java
index d591ecc..5cc9938 100644
--- a/src/main/java/jp/ac/titech/c/se/stein/util/ProcessRunner.java
+++ b/src/main/java/jp/ac/titech/c/se/stein/util/ProcessRunner.java
@@ -86,5 +86,14 @@ public void close() throws IOException {
if (reader != null) {
reader.close();
}
+ try {
+ final int exitCode = proc.waitFor();
+ if (exitCode != 0) {
+ log.warn("Process exited with code {}: {}", exitCode, c);
+ }
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ log.warn("Interrupted while waiting for process: {}", c);
+ }
}
}
From 9b1d24bdbf640e5d774d0b60b5343f5b2e460614 Mon Sep 17 00:00:00 2001
From: Shinpei Hayashi
Date: Sun, 29 Mar 2026 09:11:57 +0900
Subject: [PATCH 5/6] use a thread for writing
---
.../ac/titech/c/se/stein/util/ProcessRunner.java | 16 +++++++++++-----
1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/src/main/java/jp/ac/titech/c/se/stein/util/ProcessRunner.java b/src/main/java/jp/ac/titech/c/se/stein/util/ProcessRunner.java
index 5cc9938..64cf53b 100644
--- a/src/main/java/jp/ac/titech/c/se/stein/util/ProcessRunner.java
+++ b/src/main/java/jp/ac/titech/c/se/stein/util/ProcessRunner.java
@@ -48,17 +48,23 @@ public ProcessRunner(final String[] cmdline, final Context c) throws IOException
}
/**
- * Runs the given command, writing {@code input} to its stdin.
+ * Runs the given command, writing {@code input} to its stdin in a separate thread
+ * to avoid deadlock when the command's stdout buffer fills up.
*/
public ProcessRunner(final String[] cmdline, final byte[] input, final Context c) throws IOException {
this.proc = new ProcessBuilder()
.command(cmdline)
.redirectError(ProcessBuilder.Redirect.INHERIT)
.start();
- // FIXME: does not work if the target command blocks
- try (final OutputStream out = proc.getOutputStream()) {
- out.write(input);
- }
+ final Thread writer = new Thread(() -> {
+ try (final OutputStream out = proc.getOutputStream()) {
+ out.write(input);
+ } catch (IOException e) {
+ log.warn("Failed to write to stdin: {} {}", e.getMessage(), c);
+ }
+ });
+ writer.setDaemon(true);
+ writer.start();
this.c = c;
}
From cf94df3ff5a8529dbe40322c078066a37f30688c Mon Sep 17 00:00:00 2001
From: Shinpei Hayashi
Date: Sun, 29 Mar 2026 09:15:34 +0900
Subject: [PATCH 6/6] add comments
---
src/main/java/jp/ac/titech/c/se/stein/util/ProcessRunner.java | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/main/java/jp/ac/titech/c/se/stein/util/ProcessRunner.java b/src/main/java/jp/ac/titech/c/se/stein/util/ProcessRunner.java
index 64cf53b..df9c72a 100644
--- a/src/main/java/jp/ac/titech/c/se/stein/util/ProcessRunner.java
+++ b/src/main/java/jp/ac/titech/c/se/stein/util/ProcessRunner.java
@@ -70,6 +70,7 @@ public ProcessRunner(final String[] cmdline, final byte[] input, final Context c
/**
* Returns a reader for the process's stdout. The reader is closed when this runner is closed.
+ * Mutually exclusive with {@link #getResult()}.
*/
public BufferedReader getResultReader() {
reader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
@@ -78,6 +79,7 @@ public BufferedReader getResultReader() {
/**
* Reads and returns the entire stdout as a byte array.
+ * Mutually exclusive with {@link #getResultReader()}.
*/
public byte[] getResult() {
try (final InputStream in = proc.getInputStream()) {