Skip to content

Commit 137d923

Browse files
#173: use force update mode for ide-urls (#155) #6: fixed git pull hangs
1 parent 9eb8d46 commit 137d923

12 files changed

+885
-140
lines changed

cli/src/main/java/com/devonfw/tools/ide/context/AbstractIdeContext.java

+13-111
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
import java.net.InetAddress;
55
import java.nio.file.Files;
66
import java.nio.file.Path;
7-
import java.nio.file.attribute.FileTime;
8-
import java.time.Duration;
97
import java.util.HashMap;
108
import java.util.Iterator;
119
import java.util.List;
@@ -39,7 +37,6 @@
3937
import com.devonfw.tools.ide.os.SystemInfoImpl;
4038
import com.devonfw.tools.ide.process.ProcessContext;
4139
import com.devonfw.tools.ide.process.ProcessContextImpl;
42-
import com.devonfw.tools.ide.process.ProcessErrorHandling;
4340
import com.devonfw.tools.ide.process.ProcessResult;
4441
import com.devonfw.tools.ide.property.Property;
4542
import com.devonfw.tools.ide.repo.CustomToolRepository;
@@ -54,6 +51,8 @@
5451
*/
5552
public abstract class AbstractIdeContext implements IdeContext {
5653

54+
private static final String IDE_URLS_GIT = "https://github.com/devonfw/ide-urls.git";
55+
5756
private final Map<IdeLogLevel, IdeSubLogger> loggers;
5857

5958
private final Path ideHome;
@@ -120,8 +119,6 @@ public abstract class AbstractIdeContext implements IdeContext {
120119

121120
private UrlMetadata urlMetadata;
122121

123-
private static final Duration GIT_PULL_CACHE_DELAY_MILLIS = Duration.ofMillis(30 * 60 * 1000);
124-
125122
/**
126123
* The constructor.
127124
*
@@ -186,10 +183,11 @@ public AbstractIdeContext(IdeLogLevel minLogLevel, Function<IdeLogLevel, IdeSubL
186183
Path rootPath = Path.of(root);
187184
if (Files.isDirectory(rootPath)) {
188185
if (!ideRootPath.equals(rootPath)) {
189-
warning("Variable IDE_ROOT is set to '{}' but for your project '{}' would have been expected.");
190-
ideRootPath = rootPath;
186+
warning(
187+
"Variable IDE_ROOT is set to '{}' but for your project '{}' the path '{}' would have been expected.",
188+
root, this.ideHome.getFileName(), ideRootPath);
191189
}
192-
ideRootPath = this.ideHome.getParent();
190+
ideRootPath = rootPath;
193191
} else {
194192
warning("Variable IDE_ROOT is not set to a valid directory '{}'." + root);
195193
ideRootPath = null;
@@ -266,10 +264,7 @@ public String getMessageIdeHome() {
266264
*/
267265
public boolean isTest() {
268266

269-
if (isMock()) {
270-
return true;
271-
}
272-
return false;
267+
return isMock();
273268
}
274269

275270
/**
@@ -496,7 +491,7 @@ public UrlMetadata getUrls() {
496491

497492
if (this.urlMetadata == null) {
498493
if (!isTest()) {
499-
gitPullOrCloneIfNeeded(this.urlsPath, "https://github.com/devonfw/ide-urls.git");
494+
this.getGitContext().pullOrFetchAndResetIfNeeded(IDE_URLS_GIT, this.urlsPath, "origin", "master");
500495
}
501496
this.urlMetadata = new UrlMetadata(this);
502497
}
@@ -566,7 +561,7 @@ public boolean isOnline() {
566561
try {
567562
int timeout = 1000;
568563
online = InetAddress.getByName("github.com").isReachable(timeout);
569-
} catch (Exception e) {
564+
} catch (Exception ignored) {
570565

571566
}
572567
return online;
@@ -596,108 +591,15 @@ public DirectoryMerger getWorkspaceMerger() {
596591
}
597592

598593
@Override
599-
public ProcessContext newProcess() {
594+
public GitContext getGitContext() {
600595

601-
ProcessContext processContext = new ProcessContextImpl(this);
602-
return processContext;
596+
return new GitContextImpl(this);
603597
}
604598

605599
@Override
606-
public void gitPullOrClone(Path target, String gitRepoUrl) {
607-
608-
Objects.requireNonNull(target);
609-
Objects.requireNonNull(gitRepoUrl);
610-
if (!gitRepoUrl.startsWith("http")) {
611-
throw new IllegalArgumentException("Invalid git URL '" + gitRepoUrl + "'!");
612-
}
613-
ProcessContext pc = newProcess().directory(target).executable("git").withEnvVar("GIT_TERMINAL_PROMPT", "0");
614-
if (Files.isDirectory(target.resolve(".git"))) {
615-
ProcessResult result = pc.addArg("remote").run(true, false);
616-
List<String> remotes = result.getOut();
617-
if (remotes.isEmpty()) {
618-
String message = "This is a local git repo with no remote - if you did this for testing, you may continue...\n"
619-
+ "Do you want to ignore the problem and continue anyhow?";
620-
askToContinue(message);
621-
} else {
622-
pc.errorHandling(ProcessErrorHandling.WARNING);
623-
result = pc.addArg("pull").run(false, false);
624-
if (!result.isSuccessful()) {
625-
String message = "Failed to update git repository at " + target;
626-
if (this.offlineMode) {
627-
warning(message);
628-
interaction("Continuing as we are in offline mode - results may be outdated!");
629-
} else {
630-
error(message);
631-
if (isOnline()) {
632-
error("See above error for details. If you have local changes, please stash or revert and retry.");
633-
} else {
634-
error(
635-
"It seems you are offline - please ensure Internet connectivity and retry or activate offline mode (-o or --offline).");
636-
}
637-
askToContinue("Typically you should abort and fix the problem. Do you want to continue anyways?");
638-
}
639-
}
640-
}
641-
} else {
642-
String branch = null;
643-
int hashIndex = gitRepoUrl.indexOf("#");
644-
if (hashIndex != -1) {
645-
branch = gitRepoUrl.substring(hashIndex + 1);
646-
gitRepoUrl = gitRepoUrl.substring(0, hashIndex);
647-
}
648-
this.fileAccess.mkdirs(target);
649-
requireOnline("git clone of " + gitRepoUrl);
650-
pc.addArg("clone");
651-
if (isQuietMode()) {
652-
pc.addArg("-q");
653-
} else {
654-
}
655-
pc.addArgs("--recursive", gitRepoUrl, "--config", "core.autocrlf=false", ".");
656-
pc.run();
657-
if (branch != null) {
658-
pc.addArgs("checkout", branch);
659-
pc.run();
660-
}
661-
}
662-
}
663-
664-
/**
665-
* Checks if the Git repository in the specified target folder needs an update by inspecting the modification time of
666-
* a magic file.
667-
*
668-
* @param urlsPath The Path to the Urls repository.
669-
* @param repoUrl The git remote URL of the Urls repository.
670-
*/
671-
672-
private void gitPullOrCloneIfNeeded(Path urlsPath, String repoUrl) {
673-
674-
Path gitDirectory = urlsPath.resolve(".git");
675-
676-
// Check if the .git directory exists
677-
if (Files.isDirectory(gitDirectory)) {
678-
Path magicFilePath = gitDirectory.resolve("HEAD");
679-
long currentTime = System.currentTimeMillis();
680-
// Get the modification time of the magic file
681-
long fileMTime;
682-
try {
683-
fileMTime = Files.getLastModifiedTime(magicFilePath).toMillis();
684-
} catch (IOException e) {
685-
throw new IllegalStateException("Could not read " + magicFilePath, e);
686-
}
600+
public ProcessContext newProcess() {
687601

688-
// Check if the file modification time is older than the delta threshold
689-
if ((currentTime - fileMTime > GIT_PULL_CACHE_DELAY_MILLIS.toMillis()) || isForceMode()) {
690-
gitPullOrClone(urlsPath, repoUrl);
691-
try {
692-
Files.setLastModifiedTime(magicFilePath, FileTime.fromMillis(currentTime));
693-
} catch (IOException e) {
694-
throw new IllegalStateException("Could not read or write in " + magicFilePath, e);
695-
}
696-
}
697-
} else {
698-
// If the .git directory does not exist, perform git clone
699-
gitPullOrClone(urlsPath, repoUrl);
700-
}
602+
return new ProcessContextImpl(this);
701603
}
702604

703605
@Override
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package com.devonfw.tools.ide.context;
2+
3+
import java.nio.file.Path;
4+
5+
import com.devonfw.tools.ide.log.IdeLogger;
6+
7+
/**
8+
* Interface for git commands with input and output of information for the user.
9+
*/
10+
public interface GitContext extends IdeLogger {
11+
12+
/**
13+
* Checks if the Git repository in the specified target folder needs an update by inspecting the modification time of
14+
* a magic file.
15+
*
16+
* @param repoUrl the git remote URL to clone from. May be suffixed with a hash-sign ('#') followed by the branch name
17+
* to check-out.
18+
* @param targetRepository the {@link Path} to the target folder where the git repository should be cloned or pulled.
19+
* It is not the parent directory where git will by default create a sub-folder by default on clone but the *
20+
* final folder that will contain the ".git" subfolder.
21+
*/
22+
void pullOrCloneIfNeeded(String repoUrl, Path targetRepository);
23+
24+
/**
25+
* Attempts a git pull and reset if required.
26+
*
27+
* @param repoUrl the git remote URL to clone from. May be suffixed with a hash-sign ('#') followed by the branch name
28+
* to check-out.
29+
* @param targetRepository the {@link Path} to the target folder where the git repository should be cloned or pulled.
30+
* It is not the parent directory where git will by default create a sub-folder by default on clone but the *
31+
* final folder that will contain the ".git" subfolder.
32+
* @param remoteName the remote name e.g. origin.
33+
* @param branchName the branch name e.g. master.
34+
*/
35+
void pullOrFetchAndResetIfNeeded(String repoUrl, Path targetRepository, String remoteName, String branchName);
36+
37+
/**
38+
* Runs a git pull or a git clone.
39+
*
40+
* @param gitRepoUrl the git remote URL to clone from. May be suffixed with a hash-sign ('#') followed by the branch
41+
* name to check-out.
42+
* @param targetRepository the {@link Path} to the target folder where the git repository should be cloned or pulled.
43+
* It is not the parent directory where git will by default create a sub-folder by default on clone but the *
44+
* final folder that will contain the ".git" subfolder.
45+
*/
46+
void pullOrClone(String gitRepoUrl, Path targetRepository);
47+
48+
/**
49+
* Runs a git clone. Throws a CliException if in offline mode.
50+
*
51+
* @param gitRepoUrl the {@link GitUrl} to use for the repository URL.
52+
* @param targetRepository the {@link Path} to the target folder where the git repository should be cloned or pulled.
53+
* It is not the parent directory where git will by default create a sub-folder by default on clone but the *
54+
* final folder that will contain the ".git" subfolder.
55+
*/
56+
void clone(GitUrl gitRepoUrl, Path targetRepository);
57+
58+
/**
59+
* Runs a git pull.
60+
*
61+
* @param targetRepository the {@link Path} to the target folder where the git repository should be cloned or pulled.
62+
* It is not the parent directory where git will by default create a sub-folder by default on clone but the *
63+
* final folder that will contain the ".git" subfolder.
64+
*/
65+
void pull(Path targetRepository);
66+
67+
/**
68+
* Runs a git reset if files were modified.
69+
*
70+
* @param targetRepository the {@link Path} to the target folder where the git repository should be cloned or pulled.
71+
* It is not the parent directory where git will by default create a sub-folder by default on clone but the *
72+
* final folder that will contain the ".git" subfolder.
73+
* @param remoteName the remote server name.
74+
* @param branchName the name of the branch.
75+
*/
76+
void reset(Path targetRepository, String remoteName, String branchName);
77+
78+
/**
79+
* Runs a git cleanup if untracked files were found.
80+
*
81+
* @param targetRepository the {@link Path} to the target folder where the git repository should be cloned or pulled.
82+
* It is not the parent directory where git will by default create a sub-folder by default on clone but the *
83+
* final folder that will contain the ".git" subfolder.
84+
*/
85+
void cleanup(Path targetRepository);
86+
87+
}

0 commit comments

Comments
 (0)