Skip to content

Commit

Permalink
Merge pull request #121 from nqminhuit/refactor-2.0.0.2
Browse files Browse the repository at this point in the history
refactor: 2.0.0.2
  • Loading branch information
nqminhuit authored Aug 6, 2024
2 parents 68b69f2 + 6042650 commit 113ffb9
Show file tree
Hide file tree
Showing 7 changed files with 253 additions and 123 deletions.
74 changes: 38 additions & 36 deletions src/main/java/org/nqm/command/GitCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
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.forEachModuleFetch;
import static org.nqm.command.Wrapper.forEachModulePruneExcept;
import static org.nqm.command.Wrapper.forEachModuleWith;
import static org.nqm.command.Wrapper.getCurrentBranchUnderPath;
Expand Down Expand Up @@ -52,34 +53,6 @@ void pull() throws IOException {
printOutput(forEachModuleDo("pull"));
}

@Command(name = GIT_STATUS, aliases = "st", description = "Show the working trees status")
void status(
@Option(names = "--one-line") boolean oneLineOpt,
@Option(names = "--sort",
description = "Valid values: ${COMPLETION-CANDIDATES}. "
+ "Default value is 'module_name'. "
+ "Note that the root module will always be on top no matter the sort") GisSort sort)
throws IOException {
Queue<String> output;
if (oneLineOpt) {
output = forEachModuleDo(GIT_STATUS, "-sb", "--ignore-submodules", "--porcelain=v2", "--gis-one-line");
} else {
output = forEachModuleDo(GIT_STATUS, "-sb", "--ignore-submodules", "--porcelain=v2");
}
var currentDirName = StdOutUtils.infof(GisStringUtils.getDirName(currentDir()));
var sorted = output.stream()
.sorted((a, b) -> sort(oneLineOpt, sort, currentDirName, a, b))
.toList();
printOutput(sorted);
var fetched = Path.of(GisConfig.currentDir(), ".git", "FETCH_HEAD");
if (Files.exists(fetched)) {
var lastFetched = Files.readAttributes(fetched, BasicFileAttributes.class).lastModifiedTime();
StdOutUtils.println(
FETCHED_AT.formatted(LocalDateTime.ofInstant(lastFetched.toInstant(), ZoneId.systemDefault())
.format(DateTimeFormatter.ofPattern("HH:mm:ss dd/MM/yyyy"))));
}
}

private static int sort(boolean oneLineOpt, GisSort sort, String currentDirName, String a, String b) {
if (a.startsWith(currentDirName)) {
return Integer.MIN_VALUE;
Expand Down Expand Up @@ -108,14 +81,49 @@ private static int sort(boolean oneLineOpt, GisSort sort, String currentDirName,
return changesB - changesA;
}

private static Collection<String> sort(boolean oneLineOpt, GisSort sort, Collection<String> output) {
var currentDirName = StdOutUtils.infof(GisStringUtils.getDirName(currentDir()));
return output.stream()
.sorted((a, b) -> sort(oneLineOpt, sort, currentDirName, a, b))
.toList();
}

private void printFetchedTime() throws IOException {
var fetched = Path.of(GisConfig.currentDir(), ".git", "FETCH_HEAD");
if (Files.exists(fetched)) {
var lastFetched = Files.readAttributes(fetched, BasicFileAttributes.class).lastModifiedTime();
StdOutUtils.println(
FETCHED_AT.formatted(LocalDateTime.ofInstant(lastFetched.toInstant(), ZoneId.systemDefault())
.format(DateTimeFormatter.ofPattern("HH:mm:ss dd/MM/yyyy"))));
}
}

@Command(name = GIT_STATUS, aliases = "st", description = "Show the working trees status")
void status(
@Option(names = "--one-line") boolean oneLineOpt,
@Option(names = "--sort",
description = "Valid values: ${COMPLETION-CANDIDATES}. "
+ "Default value is 'module_name'. "
+ "Note that the root module will always be on top no matter the sort") GisSort sort)
throws IOException {
Queue<String> output;
if (oneLineOpt) {
output = forEachModuleDo(GIT_STATUS, "-sb", "--ignore-submodules", "--porcelain=v2", "--gis-one-line");
} else {
output = forEachModuleDo(GIT_STATUS, "-sb", "--ignore-submodules", "--porcelain=v2");
}
printOutput(sort(oneLineOpt, sort, output));
printFetchedTime();
}

@Command(name = "fetch", aliases = "fe", description = "Download objects and refs from other repositories")
void fetchStatus(@Option(names = "--sort",
description = "Valid values: ${COMPLETION-CANDIDATES}. "
+ "Default value is 'module_name'. "
+ "Note that the root module will always be on top no matter the sort") GisSort sort)
throws IOException {
forEachModuleDo("fetch");
status(true, sort);
printOutput(sort(true, sort, forEachModuleFetch()));
printFetchedTime();
}

@Command(name = "rebase-current-origin", aliases = "ru",
Expand All @@ -129,12 +137,6 @@ void rebaseOrigin(@Parameters(index = "0", paramLabel = "<branch name>") String
printOutput(forEachModuleDo("rebase", "%s/%s".formatted(ORIGIN, branch)));
}

@Command(name = "fetch-origin", aliases = "fo",
description = "Download objects and refs specified by branch name from other repositories")
void fetchOrigin(@Parameters(index = "0", paramLabel = "<branch name>") String branch) throws IOException {
printOutput(forEachModuleDo("fetch", ORIGIN, "%s:%s".formatted(branch, branch)));
}

@Command(name = CHECKOUT, aliases = "co", description = "Switch branches or restore working tree files")
void checkout(@Parameters(index = "0", paramLabel = "<branch name>") String branch) throws IOException {
printOutput(forEachModuleDo(CHECKOUT, branch));
Expand Down
76 changes: 45 additions & 31 deletions src/main/java/org/nqm/command/Wrapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Objects;
import java.util.Optional;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
Expand All @@ -30,44 +30,30 @@ private Wrapper() {}

public static final String ORIGIN = "origin";

private static File isFileExist(File f) {
return f.exists() ? f : null;
}

private static File getFileMarker() {
File gitModulesFilePath;
var currentDir = currentDir();
Future<File> gitModulesFilePath;
try (var exe = Executors.newVirtualThreadPerTaskExecutor()) {
var f1 = exe.submit(() -> isFileExist(Path.of(currentDir, ".gis-modules").toFile()));
var f2 = exe.submit(() -> isFileExist(Path.of(currentDir, ".gitmodules").toFile()));
gitModulesFilePath = Stream.of(f1.get(), f2.get())
.filter(Objects::nonNull)
.findFirst()
.orElseThrow(
() -> new GisException("Could not find '.gis-modules' or '.gitmodules' under this directory!"));
gitModulesFilePath = exe.submit(() -> {
var gitModules = Path.of(currentDir, ".gitmodules").toFile();
if (gitModules.exists()) {
return gitModules;
}
var gisModules = Path.of(currentDir, ".gis-modules").toFile();
if (gisModules.exists()) {
return gisModules;
}
return null;
});
}
try {
return Optional.ofNullable(gitModulesFilePath.get()).orElseThrow(
() -> new GisException("Could not find '.gis-modules' or '.gitmodules' under this directory!"));
} catch (InterruptedException | ExecutionException e) {
GisLog.debug(e);
Thread.currentThread().interrupt();
throw new GisException(e.getMessage());
}
return gitModulesFilePath;
}

public static Queue<String> forEachModuleDo(String... args) throws IOException {
return forEachModuleWith(p -> true, args);
}

public static Queue<String> forEachModuleWith(Predicate<Path> pred, String... args) throws IOException {
var output = new ConcurrentLinkedQueue<String>();
consumeAllModules(pred, exe -> path -> exe.submit(() -> output.add(CommandVerticle.execute(path, args))));
return output;
}

public static void forEachModuleDoRebaseCurrent() throws IOException {
consumeAllModules(p -> true, exe -> path -> exe.submit(() -> {
var args = new String[] {"rebase", "%s/%s".formatted(ORIGIN, getCurrentBranchUnderPath(path))};
CommandVerticle.execute(path, args);
}));
}

private static void consumeAllModules(Predicate<Path> pred, Function<ExecutorService, Consumer<Path>> f)
Expand All @@ -93,6 +79,34 @@ private static void consumeAllModules(Predicate<Path> pred, Function<ExecutorSer
}
}

public static Queue<String> forEachModuleDo(String... args) throws IOException {
return forEachModuleWith(p -> true, args);
}

public static Queue<String> forEachModuleWith(Predicate<Path> pred, String... args) throws IOException {
var output = new ConcurrentLinkedQueue<String>();
consumeAllModules(pred, exe -> path -> exe.submit(() -> output.add(CommandVerticle.execute(path, args))));
return output;
}

public static void forEachModuleDoRebaseCurrent() throws IOException {
consumeAllModules(p -> true, exe -> path -> exe.submit(() -> {
var args = new String[] {"rebase", "%s/%s".formatted(ORIGIN, getCurrentBranchUnderPath(path))};
CommandVerticle.execute(path, args);
}));
}

public static Queue<String> forEachModuleFetch() throws IOException {
var output = new ConcurrentLinkedQueue<String>();
consumeAllModules(p -> true, exe -> path -> exe.submit(() -> {
CommandVerticle.execute(path, "fetch");
output.add(CommandVerticle.execute(
path,
GitCommand.GIT_STATUS, "-sb", "--ignore-submodules", "--porcelain=v2", "--gis-one-line"));
}));
return output;
}

public static void forEachModulePruneExcept(String mergedBranch) throws IOException {
var args = new String[] {
"for-each-ref",
Expand Down
51 changes: 29 additions & 22 deletions src/test/java/org/nqm/command/GitCommandIntTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,15 @@
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Optional;
import org.junit.jupiter.api.Test;
import org.nqm.GisException;
import org.nqm.config.GisConfig;
import org.nqm.helper.GisConfigMock;
import org.nqm.helper.GisProcessUtilsMock;
import org.nqm.helper.GitBaseTest;
Expand Down Expand Up @@ -76,6 +82,29 @@ void fetch_OK() throws IOException {
"sub_6_p master");
}

@Test
void fetch_withRootBeingGitModule_OK() throws IOException {
// given:
initGitSubmodules("sub_4_w", "sub_5_r", "sub_6_p");

// when:
gis.fetchStatus(null);

var fetched = Path.of(GisConfig.currentDir(), ".git", "FETCH_HEAD");
var lastFetched = Files.readAttributes(fetched, BasicFileAttributes.class).lastModifiedTime();
var lastFetchedStr = "(fetched at: %s)"
.formatted(LocalDateTime.ofInstant(lastFetched.toInstant(), ZoneId.systemDefault())
.format(DateTimeFormatter.ofPattern("HH:mm:ss dd/MM/yyyy")));

// then:
assertThat(stripColors.apply(outCaptor.toString())).containsExactly(
tempPath.getFileName() + " master .gitmodules sub_4_w sub_5_r sub_6_p",
"sub_4_w master",
"sub_5_r master",
"sub_6_p master",
lastFetchedStr);
}

@Test
void listBranches_withEmptyModifiedFiles_OK() throws IOException {
// given:
Expand Down Expand Up @@ -430,28 +459,6 @@ void checkout_OK() throws IOException {
"" + tempPath.getFileName());
}

@Test
void fetchOrigin_OK() throws IOException {
// given:
var repos = create_clone_gitRepositories("po_1_z", "po_2_zz", "po_3_zzz");
gis.init();
gis.spinOff("batabranch");
commitFile(repos);
System.setIn(new ByteArrayInputStream("yes".getBytes()));
gis.push("batabranch", true, true, false);
gis.spinOff("master");
commitFile(repos);

// when:
resetOutputStreamTest();
gis.fetchOrigin("batabranch");

// then:
assertThat(stripColors.apply(outCaptor.toString()))
.containsExactlyInAnyOrder("po_1_z", "po_2_zz", "po_3_zzz",
"" + tempPath.getFileName());
}

@Test
void stash_OK() throws IOException {
// given:
Expand Down
Loading

0 comments on commit 113ffb9

Please sign in to comment.