Skip to content

Instantly share code, notes, and snippets.

@johnrengelman
Last active December 31, 2015 22:39
Show Gist options
  • Save johnrengelman/8055368 to your computer and use it in GitHub Desktop.
Save johnrengelman/8055368 to your computer and use it in GitHub Desktop.
Reproducible Gradle
jar {
doLast {
long ts = fileTree('.') {
exclude 'build/**'
}.files.sort {
-(it.lastModified())
}.first().lastModified()
JarFile jf = new JarFile(archivePath)
jf.entries().each { entry ->
entry.time = ts
}
jf.close()
}
}
jar {
doLast {
long ts = fileTree('.') {
exclude 'build/**'
}.files.sort {
-(it.lastModified())
}.first().lastModified()
File newJar = new File(archivePath.parent, 'new-' + archiveName)
JarOutputStream jos = new JarOutputStream(new FileOutputStream(newJar))
JarFile jf = new JarFile(archivePath)
jf.entries().each { entry ->
cloneAndCopyEntry(jf, entry, jos, ts)
}
jos.finish()
jf.close()
}
}
void cloneAndCopyEntry(JarFile originalFile, JarEntry original, JarOutputStream jos, long newTimestamp) {
JarEntry clone = new JarEntry(original)
clone.time = newTimestamp
def entryIs = originalFile.getInputStream(original)
jos.putNextEntry(clone)
copyBinaryData(entryIs, jos)
}
void copyBinaryData(InputStream is, JarOutputStream jos) {
byte[] buffer = new byte[1024]
int len = 0
while((len = is.read(buffer)) != -1) {
jos.write(buffer, 0, len)
}
}
jar {
doLast {
long ts = fileTree('.') {
exclude 'build/**'
}.files.sort {
-(it.lastModified())
}.first().lastModified()
File newJar = new File(archivePath.parent, 'new-' + archiveName)
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(newJar))
JarFile jf = new JarFile(archivePath)
jf.entries().each { entry ->
cloneAndCopyEntry(jf, entry, zos, ts)
}
zos.finish()
jf.close()
}
}
void cloneAndCopyEntry(JarFile originalFile, JarEntry original, ZipOutputStream zos, long newTimestamp) {
ZipEntry clone = new ZipEntry(original)
clone.time = newTimestamp
def entryIs = originalFile.getInputStream(original)
zos.putNextEntry(clone)
copyBinaryData(entryIs, zos)
}
void copyBinaryData(InputStream is, ZipOutputStream zos) {
byte[] buffer = new byte[1024]
int len = 0
while((len = is.read(buffer)) != -1) {
zos.write(buffer, 0, len)
}
}
jar {
doLast {
long ts = fileTree('.') {
exclude 'build/**'
}.files.sort {
-(it.lastModified())
}.first().lastModified()
File newJar = new File(archivePath.parent, 'new-' + archiveName)
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(newJar))
JarFile jf = new JarFile(archivePath)
jf.entries().each { entry ->
cloneAndCopyEntry(jf, entry, zos, ts)
}
zos.finish()
jf.close()
compareJars(archivePath, newJar, ts)
}
}
void compareJars(File original, File copy, long ts) {
def jf = new JarFile(original)
def cjf = new JarFile(copy)
jf.entries().each { entry ->
def centry = cjf.getJarEntry(entry.name)
compareEntries(entry, centry, ts)
}
}
void compareEntries(JarEntry entry, JarEntry centry, long ts) {
assert entry.name == centry.name
assert entry.comment == centry.comment
assert entry.compressedSize == centry.compressedSize
assert entry.crc == centry.crc
assert entry.extra == centry.extra
assert entry.method == centry.method
assert entry.size == centry.size
assert ts == centry.time
assert entry.hashCode() == centry.hashCode()
}
void cloneAndCopyEntry(JarFile originalFile, JarEntry original, ZipOutputStream zos, long newTimestamp) {
ZipEntry clone = new ZipEntry(original)
clone.time = newTimestamp
def entryIs = originalFile.getInputStream(original)
zos.putNextEntry(clone)
copyBinaryData(entryIs, zos)
}
void copyBinaryData(InputStream is, ZipOutputStream zos) {
byte[] buffer = new byte[1024]
int len = 0
while((len = is.read(buffer)) != -1) {
zos.write(buffer, 0, len)
}
}
jar {
doLast {
long ts = fileTree('.') {
exclude 'build/**'
}.files.sort {
-(it.lastModified())
}.first().lastModified()
File newJar = new File(archivePath.parent, 'new-' + archiveName)
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(newJar))
JarFile jf = new JarFile(archivePath)
jf.entries().each { entry ->
long adjustedTs = convertTimestamp(ts)
cloneAndCopyEntry(jf, entry, zos, adjustedTs)
}
zos.finish()
jf.close()
compareJars(archivePath, newJar, ts)
}
}
long convertTimestamp(long timestamp) {
long seconds = timestamp / 1000
if (seconds % 2 != 0) {
seconds += 1
}
return 1000 * seconds
}
void compareJars(File original, File copy, long ts) {
def jf = new JarFile(original)
def cjf = new JarFile(copy)
long adjustedTs = convertTimestamp(ts)
jf.entries().each { entry ->
def centry = cjf.getJarEntry(entry.name)
compareEntries(entry, centry, adjustedTs)
}
}
void compareEntries(JarEntry entry, JarEntry centry, long ts) {
assert entry.name == centry.name
assert entry.comment == centry.comment
assert entry.compressedSize == centry.compressedSize
assert entry.crc == centry.crc
assert entry.extra == centry.extra
assert entry.method == centry.method
assert entry.size == centry.size
assert ts == centry.time
assert entry.hashCode() == centry.hashCode()
}
void cloneAndCopyEntry(JarFile originalFile, JarEntry original, ZipOutputStream zos, long newTimestamp) {
ZipEntry clone = new ZipEntry(original)
clone.time = newTimestamp
def entryIs = originalFile.getInputStream(original)
zos.putNextEntry(clone)
copyBinaryData(entryIs, zos)
}
void copyBinaryData(InputStream is, ZipOutputStream zos) {
byte[] buffer = new byte[1024]
int len = 0
while((len = is.read(buffer)) != -1) {
zos.write(buffer, 0, len)
}
}
package john.app;
import groovy.lang.Closure;
import groovy.lang.GroovyObject;
import groovy.lang.MetaClass;
import john.lib.EchoUtil;
import org.codehaus.groovy.runtime.GeneratedClosure;
import org.codehaus.groovy.runtime.callsite.CallSite;
public class EchoApp
implements GroovyObject
{
public EchoApp()
{
EchoApp this;
CallSite[] arrayOfCallSite = $getCallSiteArray();
MetaClass localMetaClass = $getStaticMetaClass();
this.metaClass = localMetaClass;
}
public static void main(String[] args)
{
CallSite[] arrayOfCallSite = $getCallSiteArray(); arrayOfCallSite[0].call(args, new _main_closure1(EchoApp.class)); }
static { __$swapInit();
long l1 = 0L;
__timeStamp__239_neverHappen1387493347537 = l1;
long l2 = 1387493347537L; }
class _main_closure1 extends Closure implements GeneratedClosure { public _main_closure1(Object _thisObject) { super(_thisObject); }
public Object doCall(Object it) { CallSite[] arrayOfCallSite = $getCallSiteArray(); return arrayOfCallSite[0].call(EchoUtil.class, it);
}
public Object doCall()
{
CallSite[] arrayOfCallSite = $getCallSiteArray();
return doCall(null);
}
static
{
__$swapInit();
}
}
}
package john.app
import john.lib.EchoUtil
class EchoApp {
public static void main(String[] args) {
args.each {
EchoUtil.echo(it)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment