Skip to content

Commit 09c6754

Browse files
committed
Fix a few bugs and add up-to-date check for make patches
1 parent 8ac3867 commit 09c6754

File tree

6 files changed

+128
-49
lines changed

6 files changed

+128
-49
lines changed

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ plugins {
1212
}
1313

1414
group = 'net.minecrell'
15-
version = '0.1.1'
15+
version = '0.2-SNAPSHOT'
1616
description = 'A Gradle plugin to manage patches for Git repositories'
1717

1818
sourceCompatibility = 1.6

src/main/groovy/net/minecrell/gitpatcher/git/MailPatch.groovy

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,15 @@ class MailPatch {
5555
return author == commit.authorIdent && message == commit.fullMessage
5656
}
5757

58-
static MailPatch parse(InputStream is) {
59-
return parse(is.newReader('UTF-8'))
58+
static MailPatch parseHeader(byte[] data) {
59+
return parseHeader(new ByteArrayInputStream(data))
6060
}
6161

62-
static MailPatch parse(BufferedReader reader) {
62+
static MailPatch parseHeader(InputStream is) {
63+
return parseHeader(is.newReader('UTF-8'))
64+
}
65+
66+
static MailPatch parseHeader(BufferedReader reader) {
6367
String from = null
6468
String time = null
6569
StringBuilder builder = null
@@ -149,25 +153,14 @@ class MailPatch {
149153

150154
def formatter = new DiffFormatter(out)
151155
formatter.repository = repo
152-
formatter.format(commit.getParent(0).tree, commit.tree)
156+
try {
157+
Patcher.formatPatch(formatter, commit)
158+
} finally {
159+
formatter.release()
160+
}
153161

154162
writer << '-- \n' << JGIT_VERSION << '\n'
155163
writer.flush()
156164
}
157165

158-
159-
static String suggestFileName(RevCommit commit, int num) {
160-
def result = new StringBuilder(String.format("%04d-", num))
161-
for (char c : commit.shortMessage.chars) {
162-
if (Character.isLetter(c) || Character.isDigit(c)) {
163-
result << c
164-
} else if (Character.isWhitespace(c) || c == '/' as char) {
165-
result << '-' as char
166-
}
167-
}
168-
169-
result << '.patch'
170-
return result.toString()
171-
}
172-
173166
}

src/main/groovy/net/minecrell/gitpatcher/git/Patcher.groovy

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@ import static org.eclipse.jgit.revwalk.RevSort.TOPO
2727
import groovy.transform.stc.ClosureParams
2828
import groovy.transform.stc.FirstParam
2929
import groovy.transform.stc.SimpleType
30+
import org.apache.commons.lang.StringUtils
3031
import org.eclipse.jgit.api.Git
32+
import org.eclipse.jgit.diff.DiffFormatter
33+
import org.eclipse.jgit.revwalk.RevCommit
3134
import org.eclipse.jgit.revwalk.RevWalk
3235

3336
final class Patcher {
@@ -57,4 +60,28 @@ final class Patcher {
5760
return walk
5861
}
5962

63+
static File[] findPatches(File patchDir) {
64+
return patchDir.listFiles({ dir, name ->
65+
name.endsWith('.patch') && StringUtils.isNumeric(name.substring(0, 4))
66+
} as FilenameFilter).sort()
67+
}
68+
69+
static String suggestFileName(RevCommit commit, int num) {
70+
def result = new StringBuilder(String.format("%04d-", num))
71+
for (char c : commit.shortMessage.chars) {
72+
if (Character.isLetter(c) || Character.isDigit(c)) {
73+
result << c
74+
} else if (Character.isWhitespace(c) || c == '/' as char) {
75+
result << '-' as char
76+
}
77+
}
78+
79+
result << '.patch'
80+
return result.toString()
81+
}
82+
83+
static void formatPatch(DiffFormatter formatter, RevCommit commit) {
84+
formatter.format(commit.getParent(0).tree, commit.tree)
85+
}
86+
6087
}

src/main/groovy/net/minecrell/gitpatcher/task/patch/ApplyPatchesTask.groovy

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,11 @@ package net.minecrell.gitpatcher.task.patch
2323

2424
import static net.minecrell.gitpatcher.git.Patcher.withGit
2525
import static org.eclipse.jgit.api.Git.wrap
26+
import static org.eclipse.jgit.api.ResetCommand.ResetType.HARD
2627
import static org.eclipse.jgit.submodule.SubmoduleWalk.getSubmoduleRepository
2728

2829
import net.minecrell.gitpatcher.git.MailPatch
30+
import net.minecrell.gitpatcher.git.Patcher
2931
import org.eclipse.jgit.api.Git
3032
import org.gradle.api.tasks.TaskAction
3133

@@ -58,30 +60,35 @@ class ApplyPatchesTask extends PatchTask {
5860
logger.lifecycle 'Resetting {}...', repo
5961

6062
fetch().setRemote('origin').call()
61-
branchCreate()
62-
.setName('master')
63-
.setForce(true)
64-
.setStartPoint('origin/upstream')
65-
.call()
63+
64+
if (repository.getRef('master') == null) {
65+
// Create the master branch
66+
branchCreate().setName('master').call()
67+
}
68+
69+
checkout().setName('master').call()
70+
reset().setMode(HARD).setRef('origin/upstream').call()
6671
clean().setCleanDirectories(true).call()
6772

68-
logger.lifecycle 'Applying patches from {} to {}', patchDir, repo
73+
if (patchDir.isDirectory()) {
74+
logger.lifecycle 'Applying patches from {} to {}', patchDir, repo
6975

70-
for (def file : patchDir.listFiles({ dir, name -> name.endsWith('.patch') } as FilenameFilter).sort()) {
71-
logger.lifecycle 'Applying: {}', file.name
76+
for (def file : Patcher.findPatches(patchDir)) {
77+
logger.lifecycle 'Applying: {}', file.name
7278

73-
def data = new ByteArrayInputStream(file.bytes)
74-
def patch = MailPatch.parse(data)
75-
data.reset()
79+
def data = new ByteArrayInputStream(file.bytes)
80+
def patch = MailPatch.parseHeader(data)
81+
data.reset()
7682

77-
apply().setPatch(data).call()
78-
commit().setAuthor(patch.author)
79-
.setMessage(patch.message)
80-
.setAll(true)
81-
.call()
82-
}
83+
apply().setPatch(data).call()
84+
commit().setAuthor(patch.author)
85+
.setMessage(patch.message)
86+
.setAll(true)
87+
.call()
88+
}
8389

84-
logger.lifecycle 'Successfully applied patches from {} to {}', patchDir, repo
90+
logger.lifecycle 'Successfully applied patches from {} to {}', patchDir, repo
91+
}
8592
}
8693
}
8794

src/main/groovy/net/minecrell/gitpatcher/task/patch/MakePatchesTask.groovy

Lines changed: 61 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,31 +25,85 @@ import static net.minecrell.gitpatcher.git.Patcher.log
2525
import static net.minecrell.gitpatcher.git.Patcher.openGit
2626

2727
import net.minecrell.gitpatcher.git.MailPatch
28-
import org.apache.commons.io.FileUtils
28+
import net.minecrell.gitpatcher.git.Patcher
29+
import org.eclipse.jgit.diff.DiffFormatter
30+
import org.eclipse.jgit.patch.Patch
2931
import org.gradle.api.tasks.TaskAction
3032

3133
class MakePatchesTask extends PatchTask {
3234

3335
@TaskAction
3436
void makePatches() {
37+
File[] patches
3538
if (patchDir.isDirectory()) {
36-
FileUtils.cleanDirectory(patchDir)
39+
patches = Patcher.findPatches(patchDir)
3740
} else {
38-
assert patchDir.mkdirs()
41+
assert patchDir.mkdirs(), 'Failed to create patch directory'
42+
patches = null
3943
}
4044

4145
openGit(repo) {
42-
def counter = 0
46+
def i = 0
4347
for (def commit : log(it, 'origin/upstream')) {
44-
counter++
48+
def out = new File(patchDir, Patcher.suggestFileName(commit, i+1))
49+
50+
if (patches != null && i < patches.length) {
51+
def current = patches[i]
52+
if (out == current) {
53+
// The patches are possibly the same - continue checking
54+
def bytes = current.bytes
55+
def header = MailPatch.parseHeader(bytes)
56+
57+
if (header.represents(commit)) {
58+
def diff = new ByteArrayOutputStream(current.bytes.length)
59+
def formatter = new DiffFormatter(diff)
60+
formatter.repository = repository
61+
62+
try {
63+
// The commit header is the same, now check the diff
64+
def patch = new Patch()
65+
patch.parse(bytes, 0, bytes.length)
66+
67+
formatter.format(patch.files)
68+
def currentDiff = diff.toByteArray()
69+
70+
diff.reset()
71+
Patcher.formatPatch(formatter, commit)
72+
def newDiff = diff.toByteArray()
73+
74+
if (currentDiff == newDiff) {
75+
// The patches are identical, we can skip this
76+
logger.lifecycle 'Skipping patch: {} (up-to-date)', current.name
77+
i++
78+
continue
79+
}
80+
} finally {
81+
formatter.release()
82+
}
83+
84+
}
85+
} else {
86+
// Delete the old patch
87+
assert current.delete(), 'Failed to delete patch'
88+
}
89+
}
90+
4591

46-
def out = new File(patchDir, MailPatch.suggestFileName(commit, counter))
4792
logger.lifecycle 'Generating patch: {}', out.name
4893

49-
assert out.createNewFile()
94+
out.createNewFile()
5095
out.withOutputStream {
5196
MailPatch.writePatch(repository, commit, it)
5297
}
98+
99+
i++
100+
}
101+
102+
// Delete patches that don't exist anymore
103+
if (patches != null && i < patches.length) {
104+
for (; i < patches.length; i++) {
105+
assert patches[i].delete(), 'Failed to delete patch'
106+
}
53107
}
54108
}
55109
}

src/main/groovy/net/minecrell/gitpatcher/task/patch/PatchTask.groovy

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,13 @@
2121
*/
2222
package net.minecrell.gitpatcher.task.patch
2323

24-
import net.minecrell.gitpatcher.task.GitTask
24+
import net.minecrell.gitpatcher.task.SubmoduleTask
2525
import org.gradle.api.tasks.InputDirectory
2626

27-
abstract class PatchTask extends GitTask {
27+
abstract class PatchTask extends SubmoduleTask {
2828

2929
File root
3030

31-
String submodule
32-
3331
@InputDirectory
3432
File patchDir
3533

0 commit comments

Comments
 (0)