Skip to content

Commit 3f7fd65

Browse files
committed
if there is a checkout conflict, switch to another directory for the checkout
1 parent 73dc379 commit 3f7fd65

File tree

1 file changed

+160
-162
lines changed

1 file changed

+160
-162
lines changed

src/main/java/org/commonwl/view/git/GitService.java

Lines changed: 160 additions & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.eclipse.jgit.api.Git;
2525
import org.eclipse.jgit.api.errors.GitAPIException;
2626
import org.eclipse.jgit.api.errors.RefNotFoundException;
27+
import org.eclipse.jgit.api.errors.CheckoutConflictException;
2728
import org.eclipse.jgit.lib.ObjectId;
2829
import org.eclipse.jgit.lib.PersonIdent;
2930
import org.eclipse.jgit.revwalk.RevCommit;
@@ -50,166 +51,163 @@
5051
@Service
5152
public class GitService {
5253

53-
private final Logger logger = LoggerFactory.getLogger(this.getClass());
54-
55-
// Location to check out git repositories into
56-
private Path gitStorage;
57-
58-
// Whether submodules are also cloned
59-
private boolean cloneSubmodules;
60-
61-
@Autowired
62-
public GitService(@Value("${gitStorage}") Path gitStorage,
63-
@Value("${gitAPI.cloneSubmodules}") boolean cloneSubmodules) {
64-
this.gitStorage = gitStorage;
65-
this.cloneSubmodules = cloneSubmodules;
66-
}
67-
68-
/**
69-
* Gets a repository, cloning into a local directory or
70-
* @param gitDetails The details of the Git repository
71-
* @param reuseDir Whether the cached repository can be used
72-
* @return The git object for the repository
73-
*/
74-
public Git getRepository(GitDetails gitDetails, boolean reuseDir)
75-
throws GitAPIException, IOException {
76-
Git repo;
77-
if (reuseDir) {
78-
// Base dir from configuration, name from hash of repository URL
79-
String baseName = DigestUtils.sha1Hex(GitDetails.normaliseUrl(gitDetails.getRepoUrl()));
80-
81-
// Check if folder already exists
82-
Path repoDir = gitStorage.resolve(baseName);
83-
if (Files.isReadable(repoDir) && Files.isDirectory(repoDir)) {
84-
repo = Git.open(repoDir.toFile());
85-
repo.fetch().call();
86-
} else {
87-
// Create a folder and clone repository into it
88-
Files.createDirectory(repoDir);
89-
repo = cloneRepo(gitDetails.getRepoUrl(), repoDir.toFile());
90-
}
91-
} else {
92-
// Another thread is already using the existing folder
93-
// Must create another temporary one
94-
repo = cloneRepo(gitDetails.getRepoUrl(), createTempDir());
95-
}
96-
97-
// Checkout the specific branch or commit ID
98-
if (repo != null) {
99-
// Create a new local branch if it does not exist and not a commit ID
100-
String branchOrCommitId = gitDetails.getBranch();
101-
final boolean isId = ObjectId.isId(branchOrCommitId);
102-
if (!isId) {
103-
branchOrCommitId = "refs/remotes/origin/" + branchOrCommitId;
104-
}
105-
try {
106-
repo.checkout()
107-
.setName(branchOrCommitId)
108-
.call();
109-
}
110-
catch (Exception ex) {
111-
// Maybe it was a tag
112-
if (!isId && ex instanceof RefNotFoundException) {
113-
final String tag = gitDetails.getBranch();
114-
try {
115-
repo.checkout()
116-
.setName(tag)
117-
.call();
118-
}
119-
catch (Exception ex2) {
120-
// Throw the first exception, to keep the same behavior as before.
121-
throw ex;
122-
}
123-
}
124-
else {
125-
throw ex;
126-
}
127-
}
128-
}
129-
130-
return repo;
131-
}
132-
133-
/**
134-
* Gets the commit ID of the HEAD for the given repository
135-
* @param repo The Git repository
136-
* @return The commit ID of the HEAD for the repository
137-
* @throws IOException If the HEAD is detached
138-
*/
139-
public String getCurrentCommitID(Git repo) throws IOException {
140-
return repo.getRepository().findRef("HEAD").getObjectId().getName();
141-
}
142-
143-
/**
144-
* Gets a set of authors for a path in a given repository
145-
* @param repo The git repository
146-
* @param path The path to get commits for
147-
* @return An iterable of commits
148-
* @throws GitAPIException Any API errors which may occur
149-
* @throws URISyntaxException Error constructing mailto link
150-
*/
151-
public Set<HashableAgent> getAuthors(Git repo, String path) throws GitAPIException, URISyntaxException {
152-
Iterable<RevCommit> logs = repo.log().addPath(path).call();
153-
Set<HashableAgent> fileAuthors = new HashSet<>();
154-
for (RevCommit rev : logs) {
155-
// Use author first with backup of committer
156-
PersonIdent author = rev.getAuthorIdent();
157-
if (author == null) {
158-
author = rev.getCommitterIdent();
159-
}
160-
// Create a new agent and add as much detail as possible
161-
if (author != null) {
162-
HashableAgent newAgent = new HashableAgent();
163-
String name = author.getName();
164-
if (name != null && name.length() > 0) {
165-
newAgent.setName(author.getName());
166-
}
167-
String email = author.getEmailAddress();
168-
if (email != null && email.length() > 0) {
169-
newAgent.setUri(new URI("mailto:" + author.getEmailAddress()));
170-
}
171-
fileAuthors.add(newAgent);
172-
}
173-
}
174-
return fileAuthors;
175-
}
176-
177-
/**
178-
* Transfers part of the path to the branch to fix / in branch names
179-
* @param githubInfo The current Github info possibly with
180-
* part of the branch name in the path
181-
* @return A potentially corrected set of Github details,
182-
* or null if there are no slashes in the path
183-
*/
184-
public GitDetails transferPathToBranch(GitDetails githubInfo) {
185-
String path = githubInfo.getPath();
186-
String branch = githubInfo.getBranch();
187-
188-
int firstSlash = path.indexOf("/");
189-
if (firstSlash > 0) {
190-
branch += "/" + path.substring(0, firstSlash);
191-
path = path.substring(firstSlash + 1);
192-
GitDetails newDetails = new GitDetails(githubInfo.getRepoUrl(), branch, path);
193-
newDetails.setPackedId(githubInfo.getPackedId());
194-
return newDetails;
195-
} else {
196-
return null;
197-
}
198-
}
199-
200-
/**
201-
* Clones a Git repository
202-
* @param repoUrl the url of the Git repository
203-
* @param directory the directory to clone the repo into
204-
* @return a Git instance
205-
* @throws GitAPIException if any error occurs cloning the repo
206-
*/
207-
protected Git cloneRepo(String repoUrl, File directory) throws GitAPIException {
208-
return Git.cloneRepository()
209-
.setCloneSubmodules(cloneSubmodules)
210-
.setURI(repoUrl)
211-
.setDirectory(directory)
212-
.setCloneAllBranches(true)
213-
.call();
214-
}
54+
private final Logger logger = LoggerFactory.getLogger(this.getClass());
55+
56+
// Location to check out git repositories into
57+
private Path gitStorage;
58+
59+
// Whether submodules are also cloned
60+
private boolean cloneSubmodules;
61+
62+
@Autowired
63+
public GitService(@Value("${gitStorage}") Path gitStorage,
64+
@Value("${gitAPI.cloneSubmodules}") boolean cloneSubmodules) {
65+
this.gitStorage = gitStorage;
66+
this.cloneSubmodules = cloneSubmodules;
67+
}
68+
69+
/**
70+
* Gets a repository, cloning into a local directory or
71+
*
72+
* @param gitDetails The details of the Git repository
73+
* @param reuseDir Whether the cached repository can be used
74+
* @return The git object for the repository
75+
*/
76+
public Git getRepository(GitDetails gitDetails, boolean reuseDir) throws GitAPIException, IOException {
77+
Git repo;
78+
if (reuseDir) {
79+
// Base dir from configuration, name from hash of repository URL
80+
String baseName = DigestUtils.sha1Hex(GitDetails.normaliseUrl(gitDetails.getRepoUrl()));
81+
82+
// Check if folder already exists
83+
Path repoDir = gitStorage.resolve(baseName);
84+
if (Files.isReadable(repoDir) && Files.isDirectory(repoDir)) {
85+
repo = Git.open(repoDir.toFile());
86+
repo.fetch().call();
87+
} else {
88+
// Create a folder and clone repository into it
89+
Files.createDirectory(repoDir);
90+
try {
91+
repo = cloneRepo(gitDetails.getRepoUrl(), repoDir.toFile());
92+
} catch (CheckoutConflictException ex) {
93+
repo = cloneRepo(gitDetails.getRepoUrl(), createTempDir());
94+
}
95+
}
96+
} else {
97+
// Another thread is already using the existing folder
98+
// Must create another temporary one
99+
repo = cloneRepo(gitDetails.getRepoUrl(), createTempDir());
100+
}
101+
102+
// Checkout the specific branch or commit ID
103+
if (repo != null) {
104+
// Create a new local branch if it does not exist and not a commit ID
105+
String branchOrCommitId = gitDetails.getBranch();
106+
final boolean isId = ObjectId.isId(branchOrCommitId);
107+
if (!isId) {
108+
branchOrCommitId = "refs/remotes/origin/" + branchOrCommitId;
109+
}
110+
try {
111+
repo.checkout().setName(branchOrCommitId).call();
112+
} catch (Exception ex) {
113+
// Maybe it was a tag
114+
if (!isId && ex instanceof RefNotFoundException) {
115+
final String tag = gitDetails.getBranch();
116+
try {
117+
repo.checkout().setName(tag).call();
118+
} catch (Exception ex2) {
119+
// Throw the first exception, to keep the same behavior as before.
120+
throw ex;
121+
}
122+
} else {
123+
throw ex;
124+
}
125+
}
126+
}
127+
128+
return repo;
129+
}
130+
131+
/**
132+
* Gets the commit ID of the HEAD for the given repository
133+
*
134+
* @param repo The Git repository
135+
* @return The commit ID of the HEAD for the repository
136+
* @throws IOException If the HEAD is detached
137+
*/
138+
public String getCurrentCommitID(Git repo) throws IOException {
139+
return repo.getRepository().findRef("HEAD").getObjectId().getName();
140+
}
141+
142+
/**
143+
* Gets a set of authors for a path in a given repository
144+
*
145+
* @param repo The git repository
146+
* @param path The path to get commits for
147+
* @return An iterable of commits
148+
* @throws GitAPIException Any API errors which may occur
149+
* @throws URISyntaxException Error constructing mailto link
150+
*/
151+
public Set<HashableAgent> getAuthors(Git repo, String path) throws GitAPIException, URISyntaxException {
152+
Iterable<RevCommit> logs = repo.log().addPath(path).call();
153+
Set<HashableAgent> fileAuthors = new HashSet<>();
154+
for (RevCommit rev : logs) {
155+
// Use author first with backup of committer
156+
PersonIdent author = rev.getAuthorIdent();
157+
if (author == null) {
158+
author = rev.getCommitterIdent();
159+
}
160+
// Create a new agent and add as much detail as possible
161+
if (author != null) {
162+
HashableAgent newAgent = new HashableAgent();
163+
String name = author.getName();
164+
if (name != null && name.length() > 0) {
165+
newAgent.setName(author.getName());
166+
}
167+
String email = author.getEmailAddress();
168+
if (email != null && email.length() > 0) {
169+
newAgent.setUri(new URI("mailto:" + author.getEmailAddress()));
170+
}
171+
fileAuthors.add(newAgent);
172+
}
173+
}
174+
return fileAuthors;
175+
}
176+
177+
/**
178+
* Transfers part of the path to the branch to fix / in branch names
179+
*
180+
* @param githubInfo The current Github info possibly with part of the branch
181+
* name in the path
182+
* @return A potentially corrected set of Github details, or null if there are
183+
* no slashes in the path
184+
*/
185+
public GitDetails transferPathToBranch(GitDetails githubInfo) {
186+
String path = githubInfo.getPath();
187+
String branch = githubInfo.getBranch();
188+
189+
int firstSlash = path.indexOf("/");
190+
if (firstSlash > 0) {
191+
branch += "/" + path.substring(0, firstSlash);
192+
path = path.substring(firstSlash + 1);
193+
GitDetails newDetails = new GitDetails(githubInfo.getRepoUrl(), branch, path);
194+
newDetails.setPackedId(githubInfo.getPackedId());
195+
return newDetails;
196+
} else {
197+
return null;
198+
}
199+
}
200+
201+
/**
202+
* Clones a Git repository
203+
*
204+
* @param repoUrl the url of the Git repository
205+
* @param directory the directory to clone the repo into
206+
* @return a Git instance
207+
* @throws GitAPIException if any error occurs cloning the repo
208+
*/
209+
protected Git cloneRepo(String repoUrl, File directory) throws GitAPIException {
210+
return Git.cloneRepository().setCloneSubmodules(cloneSubmodules).setURI(repoUrl).setDirectory(directory)
211+
.setCloneAllBranches(true).call();
212+
}
215213
}

0 commit comments

Comments
 (0)