|
1 | 1 | package com.alexvasilkov.gradle.git.utils
|
2 | 2 |
|
3 | 3 | import com.alexvasilkov.gradle.git.GitDependency
|
4 |
| -import org.ajoberstar.grgit.Credentials |
5 |
| -import org.ajoberstar.grgit.Grgit |
6 |
| -import org.ajoberstar.grgit.Status |
| 4 | +import org.eclipse.jgit.api.Git |
| 5 | +import org.eclipse.jgit.api.Status |
7 | 6 | import org.eclipse.jgit.errors.RepositoryNotFoundException
|
8 | 7 | import org.eclipse.jgit.lib.Constants
|
| 8 | +import org.eclipse.jgit.lib.ObjectId |
| 9 | +import org.eclipse.jgit.lib.Ref |
| 10 | +import org.eclipse.jgit.transport.CredentialsProvider |
| 11 | +import org.eclipse.jgit.transport.TagOpt |
| 12 | +import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider |
9 | 13 | import org.gradle.api.GradleException
|
10 | 14 |
|
11 | 15 | class GitUtils {
|
12 | 16 |
|
13 | 17 | private GitUtils() {}
|
14 | 18 |
|
15 |
| - static void init(GitDependency repo) { |
16 |
| - Grgit git = openGit(repo) |
| 19 | + static void init(GitDependency dep) { |
| 20 | + final Git git = openGit(dep) |
17 | 21 |
|
18 | 22 | if (git != null) {
|
19 |
| - String remoteUrl = getRemoteUrl(git) |
| 23 | + final String remoteUrl = remoteUrl(git) |
20 | 24 |
|
21 |
| - if (remoteUrl == null || remoteUrl != repo.url) { |
22 |
| - throw new GradleException("Git cannot update from ${remoteUrl} to ${repo.url}.\n" + |
23 |
| - "Delete directory '${repo.dir}' and try again.") |
| 25 | + if (remoteUrl == null || remoteUrl != dep.url) { |
| 26 | + throw new GradleException("Git cannot update from ${remoteUrl} to ${dep.url}.\n" + |
| 27 | + "Delete directory '${dep.dir}' and try again.") |
24 | 28 | }
|
25 | 29 |
|
26 |
| - String targetCommit = repo.commit |
| 30 | + final String targetCommit = dep.commit |
27 | 31 |
|
28 |
| - if (repo.keepUpdated && !isLocalCommit(git, targetCommit)) { |
29 |
| - String localCommit = git.head().id |
| 32 | + if (dep.keepUpdated && !isLocalCommit(git, targetCommit)) { |
| 33 | + final String localCommit = head(git).substring(0, 7) |
30 | 34 | Log.warn "Local version '${localCommit}' is not equal to target " +
|
31 |
| - "'${targetCommit}' for '${repo.dir}'" |
| 35 | + "'${targetCommit}' for '${dep.dir}'" |
32 | 36 |
|
33 | 37 | if (hasLocalChanges(git)) {
|
34 | 38 | throw new GradleException("Git repo cannot be updated to '${targetCommit}', " +
|
35 |
| - "'${repo.dir}' contains local changes.\n" + |
| 39 | + "'${dep.dir}' contains local changes.\n" + |
36 | 40 | "Commit or revert all changes manually.")
|
37 | 41 | } else {
|
38 |
| - Log.warn "Updating to version '${targetCommit}' for '${repo.dir}'" |
39 |
| - update(git, repo) |
| 42 | + Log.warn "Updating to version '${targetCommit}' for '${dep.dir}'" |
| 43 | + update(git, dep) |
40 | 44 | }
|
41 | 45 | }
|
42 | 46 | } else {
|
43 |
| - cloneRepo(repo) |
| 47 | + clone(dep) |
44 | 48 | }
|
45 | 49 | }
|
46 | 50 |
|
47 |
| - private static Grgit openGit(GitDependency repo) { |
| 51 | + private static Git openGit(GitDependency dep) { |
48 | 52 | try {
|
49 |
| - return Grgit.open(dir: repo.dir, credentials: getCreds(repo)) |
| 53 | + return Git.open(dep.dir) |
50 | 54 | } catch (RepositoryNotFoundException ignored) {
|
51 | 55 | return null
|
52 | 56 | }
|
53 | 57 | }
|
54 | 58 |
|
55 |
| - private static String getRemoteUrl(Grgit git) { |
56 |
| - return git.repository.jgit.repository.config |
57 |
| - .getString('remote', Constants.DEFAULT_REMOTE_NAME, 'url') |
| 59 | + private static String remoteUrl(Git git) { |
| 60 | + return git.repository.config.getString('remote', Constants.DEFAULT_REMOTE_NAME, 'url') |
58 | 61 | }
|
59 | 62 |
|
60 |
| - private static boolean isLocalCommit(Grgit git, String targetId) { |
61 |
| - def head = git.head() |
| 63 | + private static String head(Git git) { |
| 64 | + return ObjectId.toString(git.repository.resolve('HEAD')) |
| 65 | + } |
| 66 | + |
| 67 | + private static boolean isLocalCommit(Git git, String targetId) { |
62 | 68 | // Checking if local commit is equal to (starts with) requested one.
|
63 |
| - // If not then we should check if there are tags with target name pointing to current head. |
64 |
| - return head.id.startsWith(targetId) || |
65 |
| - git.tag.list().find { it.commit == head && it.name == targetId } |
| 69 | + final String headId = head(git) |
| 70 | + if (headId.startsWith(targetId)) return true |
| 71 | + |
| 72 | + // If not then we should check if there is a tag with given name pointing to current head. |
| 73 | + final Ref tag = git.repository.refDatabase.exactRef(Constants.R_TAGS + targetId) |
| 74 | + // Annotated tags need extra effort |
| 75 | + final Ref peeledTag = tag == null ? null : git.repository.refDatabase.peel(tag) |
| 76 | + final tagObjectId = peeledTag?.peeledObjectId ?: tag?.objectId |
| 77 | + |
| 78 | + final String tagId = ObjectId.toString(tagObjectId) |
| 79 | + return tagId == headId |
66 | 80 | }
|
67 | 81 |
|
68 |
| - private static boolean hasLocalChanges(Grgit git) { |
69 |
| - Status status = git.status() |
70 |
| - return !status.staged.allChanges.isEmpty() || !status.unstaged.allChanges.isEmpty() |
| 82 | + private static boolean hasLocalChanges(Git git) { |
| 83 | + final Status status = git.status().call() |
| 84 | + final List<String> changes = new ArrayList<>() |
| 85 | + changes.addAll(status.added) |
| 86 | + changes.addAll(status.changed) |
| 87 | + changes.addAll(status.removed) |
| 88 | + changes.addAll(status.untracked) |
| 89 | + changes.addAll(status.modified) |
| 90 | + changes.addAll(status.missing) |
| 91 | + return !changes.isEmpty() |
71 | 92 | }
|
72 | 93 |
|
73 | 94 | static boolean hasLocalChangesInDir(File dir) {
|
74 | 95 | try {
|
75 |
| - Grgit git = Grgit.open(dir: dir) |
76 |
| - return hasLocalChanges(git) |
| 96 | + return hasLocalChanges(Git.open(dir)) |
77 | 97 | } catch (RepositoryNotFoundException ignored) {
|
78 | 98 | return false
|
79 | 99 | }
|
80 | 100 | }
|
81 | 101 |
|
82 |
| - private static void update(Grgit git, GitDependency repo) { |
83 |
| - long start = System.currentTimeMillis() |
84 |
| - Log.info "Update started '${repo.url}' at version '${repo.commit}'" |
| 102 | + private static void update(Git git, GitDependency dep) { |
| 103 | + final long start = System.currentTimeMillis() |
| 104 | + Log.info "Update started '${dep.url}' at version '${dep.commit}'" |
| 105 | + |
85 | 106 | git.fetch()
|
86 |
| - switchToVersion(git, repo.commit) |
87 |
| - int spent = System.currentTimeMillis() - start |
| 107 | + .setTagOpt(TagOpt.FETCH_TAGS) |
| 108 | + .setCredentialsProvider(creds(dep)) |
| 109 | + .call() |
| 110 | + |
| 111 | + git.checkout().setName(dep.commit).call() |
| 112 | + |
| 113 | + final long spent = System.currentTimeMillis() - start |
88 | 114 | Log.info "Update finished ($spent ms)"
|
89 | 115 | }
|
90 | 116 |
|
91 |
| - private static void cloneRepo(GitDependency repo) { |
92 |
| - long start = System.currentTimeMillis() |
93 |
| - Log.info "Clone started '${repo.url}' at version '${repo.commit}'" |
94 |
| - Grgit git = Grgit.clone(dir: repo.dir, uri: repo.url, credentials: getCreds(repo)) |
95 |
| - switchToVersion(git, repo.commit) |
96 |
| - int spent = System.currentTimeMillis() - start |
97 |
| - Log.info "Clone finished ($spent ms)" |
98 |
| - } |
| 117 | + private static void clone(GitDependency dep) { |
| 118 | + final long start = System.currentTimeMillis() |
| 119 | + Log.info "Clone started '${dep.url}' at version '${dep.commit}'" |
99 | 120 |
|
100 |
| - private static void switchToVersion(Grgit git, String commit) { |
101 |
| - git.checkout(branch: commit) |
| 121 | + final Git git = Git.cloneRepository() |
| 122 | + .setDirectory(dep.dir) |
| 123 | + .setURI(dep.url) |
| 124 | + .setRemote('origin') |
| 125 | + .setNoCheckout(true) |
| 126 | + .setCredentialsProvider(creds(dep)) |
| 127 | + .call() |
| 128 | + |
| 129 | + git.checkout().setName(dep.commit).call() |
| 130 | + |
| 131 | + final long spent = System.currentTimeMillis() - start |
| 132 | + Log.info "Clone finished ($spent ms)" |
102 | 133 | }
|
103 | 134 |
|
104 |
| - private static Credentials getCreds(GitDependency repo) { |
105 |
| - return repo.needsAuth ? new Credentials(repo.username, repo.password) : null |
| 135 | + private static CredentialsProvider creds(GitDependency dep) { |
| 136 | + return dep.needsAuth |
| 137 | + ? new UsernamePasswordCredentialsProvider(dep.username, dep.password) : null |
106 | 138 | }
|
107 | 139 | }
|
0 commit comments