From 1fdc3c14d86d4b8d9d6cca7b9ee37ef6a89123d5 Mon Sep 17 00:00:00 2001 From: minh Date: Thu, 25 Jul 2024 09:52:31 +0700 Subject: [PATCH] feat: Re-enable rebase current origin This function was disabled after the migration of VertX to Virtual Threads due to different implementation. --- src/main/java/org/nqm/command/GitCommand.java | 25 ++----- src/main/java/org/nqm/command/Wrapper.java | 63 +++++++++++++--- .../org/nqm/command/GitCommandIntTest.java | 71 +++++++++++++++++++ src/test/java/org/nqm/helper/GitBaseTest.java | 13 ++++ 4 files changed, 146 insertions(+), 26 deletions(-) diff --git a/src/main/java/org/nqm/command/GitCommand.java b/src/main/java/org/nqm/command/GitCommand.java index ec94d8c..ce15c26 100644 --- a/src/main/java/org/nqm/command/GitCommand.java +++ b/src/main/java/org/nqm/command/GitCommand.java @@ -2,8 +2,11 @@ import static org.nqm.command.CommandVerticle.GIS_CONCAT_MODULES_NAME_OPT; import static org.nqm.command.CommandVerticle.GIS_NO_PRINT_MODULES_NAME_OPT; +import static org.nqm.command.Wrapper.ORIGIN; import static org.nqm.command.Wrapper.forEachModuleDo; +import static org.nqm.command.Wrapper.forEachModuleDoRebaseCurrent; import static org.nqm.command.Wrapper.forEachModuleWith; +import static org.nqm.command.Wrapper.getCurrentBranchUnderPath; import static org.nqm.config.GisConfig.currentDir; import java.io.BufferedReader; import java.io.FileOutputStream; @@ -22,13 +25,10 @@ import java.util.function.Predicate; import java.util.regex.Pattern; import java.util.stream.Stream; -import org.nqm.GisException; import org.nqm.config.GisConfig; -import org.nqm.config.GisLog; -import org.nqm.utils.GisProcessUtils; +import org.nqm.model.GisSort; import org.nqm.utils.GisStringUtils; import org.nqm.utils.StdOutUtils; -import org.nqm.model.GisSort; import picocli.CommandLine.Command; import picocli.CommandLine.Option; import picocli.CommandLine.Parameters; @@ -37,7 +37,6 @@ public class GitCommand { private static final String CHECKOUT = "checkout"; private static final String FETCHED_AT = "(fetched at: %s)"; - private static final String ORIGIN = "origin"; private static final Path TMP_FILE = Path.of("/", "tmp", "gis_fetch" + currentDir().replace("/", "_")); static final String GIS_AUTOCOMPLETE_FILE = "_gis"; @@ -130,8 +129,8 @@ void fetchStatus(@Option(names = "--sort", @Command(name = "rebase-current-origin", aliases = "ru", description = "Reapply commits on top of current repositories' origin") - void rebaseCurrentOrigin() { - throw new GisException("this function is in progress"); + void rebaseCurrentOrigin() throws IOException { + forEachModuleDoRebaseCurrent(); } @Command(name = "rebase-origin", aliases = "re", description = "Reapply commits on top of other base tip") @@ -298,21 +297,11 @@ private static Stream streamOf(String[] input) { return Stream.of(input).map(String::trim).distinct(); } - private String getCurrentBranchUnderPath(Path path) throws IOException { - var result = GisProcessUtils.quickRun(path.toFile(), GisConfig.GIT_HOME_DIR, "branch", "--show-current"); - return result.output().trim(); - } - private boolean isSameBranchUnderPath(String branch, Path path) { if (GisStringUtils.isBlank(branch)) { return false; } - try { - return branch.equals(getCurrentBranchUnderPath(path)); - } catch (IOException e) { - GisLog.debug(e); - throw new GisException(e.getMessage()); - } + return branch.equals(getCurrentBranchUnderPath(path)); } private boolean isConfirmed(String question) throws IOException { diff --git a/src/main/java/org/nqm/command/Wrapper.java b/src/main/java/org/nqm/command/Wrapper.java index 61a95c8..8f4338c 100644 --- a/src/main/java/org/nqm/command/Wrapper.java +++ b/src/main/java/org/nqm/command/Wrapper.java @@ -11,16 +11,22 @@ import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; +import java.util.function.Consumer; import java.util.function.Predicate; import java.util.stream.Stream; import org.nqm.GisException; +import org.nqm.config.GisConfig; import org.nqm.config.GisLog; +import org.nqm.model.GisProcessDto; +import org.nqm.utils.GisProcessUtils; import org.nqm.utils.StdOutUtils; public final class Wrapper { private Wrapper() {} + public static final String ORIGIN = "origin"; + private static File isFileExist(File f) { return f.exists() ? f : null; } @@ -44,15 +50,18 @@ private static File getFileMarker() { return gitModulesFilePath; } - public static Queue forEachModuleWith(Predicate pred, String... args) - throws IOException { + public static Queue forEachModuleDo(String... args) throws IOException { + return forEachModuleWith(p -> true, args); + } + + public static Queue forEachModuleWith(Predicate pred, String... args) throws IOException { var gitModulesFilePath = getFileMarker(); var currentDir = currentDir(); var output = new ConcurrentLinkedQueue(); try (var exe = Executors.newVirtualThreadPerTaskExecutor()) { - Optional.of(Path.of(currentDir)) - .filter(pred) - .ifPresent(root -> exe.submit(() -> output.add(CommandVerticle.execute(root, args)))); + Consumer consume = path -> exe.submit(() -> output.add(CommandVerticle.execute(path, args))); + Optional.of(Path.of(currentDir)).filter(pred).ifPresent(consume); + Files.readAllLines(gitModulesFilePath.toPath()).stream() .map(String::trim) .filter(s -> s.startsWith("path")) @@ -66,12 +75,50 @@ public static Queue forEachModuleWith(Predicate pred, String... ar return false; }) .filter(pred) - .forEach(dir -> exe.submit(() -> output.add(CommandVerticle.execute(dir, args)))); + .forEach(consume); } return output; } - public static Queue forEachModuleDo(String... args) throws IOException { - return forEachModuleWith(p -> true, args); + public static void forEachModuleDoRebaseCurrent() throws IOException { + var gitModulesFilePath = getFileMarker(); + var currentDir = currentDir(); + + try (var exe = Executors.newVirtualThreadPerTaskExecutor()) { + Consumer consume = path -> exe.submit(() -> { + var args = new String[] {"rebase", "%s/%s".formatted(ORIGIN, getCurrentBranchUnderPath(path))}; + CommandVerticle.execute(path, args); + }); + + consume.accept(Path.of(currentDir)); + + Files.readAllLines(gitModulesFilePath.toPath()).stream() + .map(String::trim) + .filter(s -> s.startsWith("path")) + .map(s -> s.replace("path = ", "")) + .map(dir -> Path.of(currentDir, dir)) + .filter(dir -> { + if (dir.toFile().exists()) { + return true; + } + StdOutUtils.errln("directory '%s' does not exist, will be ignored!".formatted("" + dir)); + return false; + }) + .forEach(consume); + } + } + + public static String getCurrentBranchUnderPath(Path path) { + GisProcessDto result; + try { + result = GisProcessUtils.quickRun(path.toFile(), GisConfig.GIT_HOME_DIR, "branch", "--show-current"); + } catch (IOException e) { + GisLog.debug(e); + throw new GisException(e.getMessage()); + } + if (result != null) { + return result.output().trim(); + } + return ""; } } diff --git a/src/test/java/org/nqm/command/GitCommandIntTest.java b/src/test/java/org/nqm/command/GitCommandIntTest.java index 2cd36dc..2d224f1 100644 --- a/src/test/java/org/nqm/command/GitCommandIntTest.java +++ b/src/test/java/org/nqm/command/GitCommandIntTest.java @@ -489,4 +489,75 @@ void stashPop_OK() throws IOException { "(use \"git restore --staged ...\" to unstage)", "new file: filescramble1"); } + + @Test + void rebaseCurrentOrigin() throws IOException { + // given: + var repos = create_clone_gitRepositories("ali_4_x", "ali_5_xx", "ali_6_xxx"); + gis.init(); + commitFile(repos); + commitFile(repos); + gis.push("master", true, true, true); + resetHead1(repos); + cleanUntrackedFiles(repos); + resetOutputStreamTest(); + + gis.status(true, null); + assertThat(stripColors.apply(outCaptor.toString())).containsOnly( + "" + tempPath.subpath(1, tempPath.getNameCount()), + "ali_4_x master[behind 1]", + "ali_5_xx master[behind 1]", + "ali_6_xxx master[behind 1]"); + + // when: + resetOutputStreamTest(); + gis.rebaseCurrentOrigin(); + + // then: + gis.status(true, null); + assertThat(stripColors.apply(outCaptor.toString())).containsOnly( + "" + tempPath.subpath(1, tempPath.getNameCount()), + "ali_4_x master", + "ali_5_xx master", + "ali_6_xxx master"); + } + + @Test + void rebaseCurrentOrigin_withEachModuleHasDifferentBranch() throws IOException { + // given: + var repos = create_clone_gitRepositories("ali_4_x", "ali_5_xx", "ali_6_xxx"); + gis.init(); + commitFile(repos); + gis.push("master", true, true, true); + gis.spinOff("bbb4", "ali_4_x"); + gis.spinOff("bbb5", "ali_5_xx"); + gis.spinOff("bbb6", "ali_6_xxx"); + commitFile(repos); + gis.push("bbb4", true, true, true); + gis.push("bbb5", true, true, true); + gis.push("bbb6", true, true, true); + resetHead1(repos); + cleanUntrackedFiles(repos); + resetOutputStreamTest(); + + gis.status(true, null); + assertThat(stripColors.apply(outCaptor.toString())).containsOnly( + "" + tempPath.subpath(1, tempPath.getNameCount()), + "ali_4_x bbb4[behind 1]", + "ali_5_xx bbb5[behind 1]", + "ali_6_xxx bbb6[behind 1]"); + + // when: + resetOutputStreamTest(); + gis.rebaseCurrentOrigin(); + + // then: + gis.status(true, null); + assertThat(stripColors.apply(outCaptor.toString())).containsOnly( + "" + tempPath.subpath(1, tempPath.getNameCount()), + "ali_4_x bbb4", + "ali_5_xx bbb5", + "ali_6_xxx bbb6"); + } + } diff --git a/src/test/java/org/nqm/helper/GitBaseTest.java b/src/test/java/org/nqm/helper/GitBaseTest.java index ad240bc..fdcabe2 100644 --- a/src/test/java/org/nqm/helper/GitBaseTest.java +++ b/src/test/java/org/nqm/helper/GitBaseTest.java @@ -155,4 +155,17 @@ protected void scrambleFiles(List repos) { } }); } + + protected void resetHead1(List repos) { + repos.forEach(repo -> { + git(repo, "reset", "HEAD~1"); + }); + } + + protected void cleanUntrackedFiles(List repos) { + repos.forEach(repo -> { + git(repo, "clean", "-fd"); + }); + } + }