Removed Dependency on FastMD5, now uses SHA1 hashes.
parent
e72e6a041e
commit
268273aaf4
|
@ -34,10 +34,9 @@
|
|||
<orderEntry type="library" name="javaparser" level="application" />
|
||||
<orderEntry type="library" name="javatar" level="application" />
|
||||
<orderEntry type="library" name="async-http-client" level="application" />
|
||||
<orderEntry type="library" name="fast-md5" level="application" />
|
||||
<orderEntry type="library" name="jsonbeans" level="application" />
|
||||
<orderEntry type="library" name="netty-all" level="application" />
|
||||
<orderEntry type="library" name="yamlbeans" level="application" />
|
||||
<orderEntry type="library" name="kryo" level="application" />
|
||||
</component>
|
||||
</module>
|
||||
</module>
|
||||
|
|
7
LICENSE
7
LICENSE
|
@ -14,13 +14,6 @@
|
|||
Copyright 2010, dorkbox, llc
|
||||
|
||||
|
||||
- FastMD5 - LGPL v3 License
|
||||
http://www.twmacinta.com/myjava/fast_md5.php
|
||||
Copyright 1996, Santeri Paavolainen, Helsinki Finland
|
||||
Many changes Copyright 2002 - 2010 Timothy W Macinta
|
||||
Originally written by Santeri Paavolainen, Helsinki Finland 1996
|
||||
|
||||
|
||||
- FilenameUtils.java (normalize + dependencies) - Apache 2.0 License
|
||||
http://commons.apache.org/proper/commons-io/
|
||||
Copyright 2013, ASF
|
||||
|
|
165
LICENSE.LGPLv3
165
LICENSE.LGPLv3
|
@ -1,165 +0,0 @@
|
|||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
|
@ -28,7 +28,6 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.bouncycastle.crypto.digests.MD5Digest;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import com.esotericsoftware.kryo.Kryo;
|
||||
|
@ -37,16 +36,15 @@ import com.esotericsoftware.kryo.io.Input;
|
|||
import com.esotericsoftware.kryo.io.Output;
|
||||
import com.esotericsoftware.minlog.Log;
|
||||
import com.esotericsoftware.wildcard.Paths;
|
||||
import com.twmacinta.util.MD5;
|
||||
|
||||
import dorkbox.BuildOptions;
|
||||
import dorkbox.BuildVersion;
|
||||
import dorkbox.Builder;
|
||||
import dorkbox.build.util.BuildLog;
|
||||
import dorkbox.build.util.Hash;
|
||||
import dorkbox.build.util.OutputFile;
|
||||
import dorkbox.build.util.ShutdownHook;
|
||||
import dorkbox.license.License;
|
||||
import dorkbox.util.Base64Fast;
|
||||
import dorkbox.util.FileUtil;
|
||||
import dorkbox.util.OS;
|
||||
import dorkbox.util.SerializationManager;
|
||||
|
@ -160,7 +158,7 @@ class Project<T extends Project<T>> {
|
|||
|
||||
try {
|
||||
String oldHash = Builder.settings.get("BUILD", String.class);
|
||||
String hashedContents = generateChecksums(paths);
|
||||
String hashedContents = Hash.generateChecksums(paths);
|
||||
|
||||
if (oldHash != null) {
|
||||
if (!oldHash.equals(hashedContents)) {
|
||||
|
@ -185,6 +183,8 @@ class Project<T extends Project<T>> {
|
|||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
Hash.forceRebuildAll = forceRebuildAll;
|
||||
}
|
||||
|
||||
public static
|
||||
|
@ -235,7 +235,6 @@ class Project<T extends Project<T>> {
|
|||
// used to make sure licenses are called in the correct spot
|
||||
private transient boolean calledLicenseBefore = false;
|
||||
|
||||
transient Paths checksumPaths = new Paths();
|
||||
protected List<License> licenses = new ArrayList<License>();
|
||||
protected BuildOptions buildOptions;
|
||||
|
||||
|
@ -259,6 +258,8 @@ class Project<T extends Project<T>> {
|
|||
// true if we should rebuild this project
|
||||
boolean forceRebuild = false;
|
||||
|
||||
protected transient Hash hash;
|
||||
|
||||
/**
|
||||
* Temporary projects are always built, but not always exported to maven (this is controlled by the parent, non-temp project
|
||||
* recursively)
|
||||
|
@ -341,6 +342,8 @@ class Project<T extends Project<T>> {
|
|||
this.stagingDir = FileUtil.normalize(STAGING + File.separator + lowerCase_outputDir);
|
||||
// must call this method, because it's not overridden by jar type
|
||||
outputFile0(new File(this.stagingDir.getParentFile(), this.name + getExtension()).getAbsolutePath(), null);
|
||||
|
||||
hash = new Hash(projectName, buildOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -522,7 +525,7 @@ class Project<T extends Project<T>> {
|
|||
*/
|
||||
public
|
||||
T depends(final Paths dependencies) {
|
||||
checksumPaths.add(dependencies);
|
||||
hash.add(dependencies);
|
||||
sourceDependencies.add(dependencies);
|
||||
|
||||
return (T) this;
|
||||
|
@ -793,111 +796,6 @@ class Project<T extends Project<T>> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//// CHECKSUM LOGIC
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Add a path to be checksum'd.
|
||||
*/
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public final
|
||||
void checksum(Paths path) {
|
||||
this.checksumPaths.add(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the checksums for path match the saved checksums and the jar file exists, false if the check failed and the
|
||||
* project needs to rebuild
|
||||
*/
|
||||
boolean verifyChecksums() throws IOException {
|
||||
if (forceRebuildAll || this.buildOptions.compiler.forceRebuild) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// check to see if our SOURCES *and check-summed files* have changed.
|
||||
String hashedContents = generateChecksums(this.checksumPaths);
|
||||
String checkContents = Builder.settings.get(this.name, String.class);
|
||||
|
||||
return hashedContents != null && hashedContents.equals(checkContents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the checksums for a given path
|
||||
*/
|
||||
void saveChecksums() throws IOException {
|
||||
// by default, we save the build. When building a 'test' build, we opt to NOT save the build hashes, so that a 'normal' build
|
||||
// will then compile.
|
||||
if (!buildOptions.compiler.saveBuild) {
|
||||
return;
|
||||
}
|
||||
|
||||
// hash/save the sources *and check-summed files* files
|
||||
String hashedContents = generateChecksums(this.checksumPaths);
|
||||
Builder.settings.save(this.name, hashedContents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates checksums for the given path
|
||||
*/
|
||||
public static
|
||||
String generateChecksum(File file) throws IOException {
|
||||
synchronized (Project.class) {
|
||||
// calculate the hash of file
|
||||
boolean found = false;
|
||||
if (file.isFile() && file.canRead()) {
|
||||
found = true;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] hashBytes = MD5.getHash(file);
|
||||
|
||||
return Base64Fast.encodeToString(hashBytes, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates checksums for the given path
|
||||
*/
|
||||
public static
|
||||
String generateChecksums(Paths... paths) throws IOException {
|
||||
synchronized (Project.class) {
|
||||
// calculate the hash of all the files in the source path
|
||||
Set<String> names = new HashSet<String>(64);
|
||||
|
||||
for (Paths path : paths) {
|
||||
names.addAll(path.getPaths());
|
||||
}
|
||||
|
||||
// hash of hash of files. faster than using java to hash files
|
||||
MD5Digest md5_digest = new MD5Digest();
|
||||
|
||||
boolean found = false;
|
||||
for (String name : names) {
|
||||
File file = new File(name);
|
||||
if (file.isFile() && file.canRead()) {
|
||||
found = true;
|
||||
|
||||
byte[] hashBytes = MD5.getHash(file);
|
||||
md5_digest.update(hashBytes, 0, hashBytes.length);
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] hashBytes = new byte[md5_digest.getDigestSize()];
|
||||
md5_digest.doFinal(hashBytes, 0);
|
||||
|
||||
return Base64Fast.encodeToString(hashBytes, false);
|
||||
}
|
||||
}
|
||||
|
||||
public
|
||||
T version(BuildVersion version) {
|
||||
this.version = version;
|
||||
|
|
|
@ -110,7 +110,7 @@ class ProjectGwt extends Project<ProjectGwt> {
|
|||
if (srcDir.endsWith("src")) {
|
||||
String parent = new File(srcDir).getAbsoluteFile()
|
||||
.getParent();
|
||||
checksum(new Paths(parent));
|
||||
hash.add(parent);
|
||||
}
|
||||
|
||||
return sourcePath(new Paths(srcDir, "./"));
|
||||
|
@ -356,16 +356,15 @@ class ProjectGwt extends Project<ProjectGwt> {
|
|||
*
|
||||
* @return true if the checksums for path match the saved checksums and the jar file exists
|
||||
*/
|
||||
@Override
|
||||
boolean verifyChecksums() throws IOException {
|
||||
boolean sourceHashesSame = super.verifyChecksums();
|
||||
boolean sourceHashesSame = hash.verifyChecksums();
|
||||
if (!sourceHashesSame) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// if the sources are the same, check the output dir
|
||||
if (this.stagingDir.exists()) {
|
||||
String dirChecksum = generateChecksum(this.stagingDir);
|
||||
String dirChecksum = hash.generateChecksum(this.stagingDir);
|
||||
String checkContents = Builder.settings.get(this.stagingDir.getAbsolutePath(), String.class);
|
||||
|
||||
return dirChecksum != null && dirChecksum.equals(checkContents);
|
||||
|
@ -377,7 +376,6 @@ class ProjectGwt extends Project<ProjectGwt> {
|
|||
/**
|
||||
* GWT only cares about the output dir (it doesn't make jars for compiling) Saves the checksums for a given path
|
||||
*/
|
||||
@Override
|
||||
void saveChecksums() throws IOException {
|
||||
// by default, we save the build. When building a 'test' build, we opt to NOT save the build hashes, so that a 'normal' build
|
||||
// will then compile.
|
||||
|
@ -385,11 +383,11 @@ class ProjectGwt extends Project<ProjectGwt> {
|
|||
return;
|
||||
}
|
||||
|
||||
super.saveChecksums();
|
||||
hash.saveChecksums();
|
||||
|
||||
// hash/save the output files (if there are any)
|
||||
if (this.stagingDir.exists()) {
|
||||
String fileChecksum = generateChecksum(this.stagingDir);
|
||||
String fileChecksum = hash.generateChecksum(this.stagingDir);
|
||||
Builder.settings.save(this.stagingDir.getAbsolutePath(), fileChecksum);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,9 +88,9 @@ public class ProjectJar extends Project<ProjectJar> {
|
|||
|
||||
public
|
||||
ProjectJar outputFileNoWarn(final String outputFile, final String outputSourceFile) {
|
||||
this.checksumPaths.addFile(outputFile);
|
||||
hash.add(outputFile);
|
||||
if (outputSourceFile != null) {
|
||||
this.checksumPaths.addFile(outputSourceFile);
|
||||
hash.add(outputSourceFile);
|
||||
}
|
||||
|
||||
return super.outputFile(outputFile, outputSourceFile);
|
||||
|
|
|
@ -98,7 +98,7 @@ class ProjectJava extends Project<ProjectJava> {
|
|||
this.sourcePaths.add(sourcePaths);
|
||||
|
||||
// ALWAYS add the source paths to be checksumed!
|
||||
checksum(sourcePaths);
|
||||
hash.add(sourcePaths);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ class ProjectJava extends Project<ProjectJava> {
|
|||
ProjectJava sourcePath(String srcDir) {
|
||||
if (srcDir.endsWith("src")) {
|
||||
String parent = new File(srcDir).getAbsoluteFile().getParent();
|
||||
checksum(new Paths(parent));
|
||||
hash.add(new Paths(parent));
|
||||
}
|
||||
|
||||
return sourcePath(new Paths(srcDir, "./"));
|
||||
|
@ -217,7 +217,7 @@ class ProjectJava extends Project<ProjectJava> {
|
|||
// also, we DO NOT check jar versions/etc here (that happens later)
|
||||
|
||||
// if true, this means that the files ARE the same and they have not changed
|
||||
final boolean b = project.verifyChecksums();
|
||||
final boolean b = project.hash.verifyChecksums();
|
||||
shouldBuild |= !b;
|
||||
}
|
||||
}
|
||||
|
@ -905,14 +905,13 @@ class ProjectJava extends Project<ProjectJava> {
|
|||
* @return true if the checksums for path match the saved checksums. If there is a JAR file, it also checks to see if it is built &
|
||||
* matches the saved checksums. If it's a temp project (and specifies a jar) the jarChecksum is ignored (so only checksums based on source code changes)
|
||||
*/
|
||||
@Override
|
||||
boolean verifyChecksums() throws IOException {
|
||||
// if temporary + we override the status, we ALWAYS build it
|
||||
if (this.temporary && this.overrideTemporary) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean sourceHashesSame = super.verifyChecksums();
|
||||
boolean sourceHashesSame = hash.verifyChecksums();
|
||||
if (!sourceHashesSame) {
|
||||
return false;
|
||||
}
|
||||
|
@ -926,7 +925,7 @@ class ProjectJava extends Project<ProjectJava> {
|
|||
final File originalOutputFile = this.outputFile.getOriginal();
|
||||
|
||||
if (originalOutputFile.canRead()) {
|
||||
String jarChecksum = generateChecksum(originalOutputFile);
|
||||
String jarChecksum = hash.generateChecksum(originalOutputFile);
|
||||
String checkContents = Builder.settings.get(this.name + ":" + originalOutputFile.getAbsolutePath(), String.class);
|
||||
|
||||
boolean outputFileGood = jarChecksum != null && jarChecksum.equals(checkContents);
|
||||
|
@ -939,7 +938,7 @@ class ProjectJava extends Project<ProjectJava> {
|
|||
final File originalOutputFileSource = this.outputFile.getSourceOriginal();
|
||||
|
||||
// now check the src.zip file (if there was one).
|
||||
jarChecksum = generateChecksum(originalOutputFileSource);
|
||||
jarChecksum = hash.generateChecksum(originalOutputFileSource);
|
||||
checkContents = Builder.settings.get(this.name + ":" + originalOutputFileSource.getAbsolutePath(), String.class);
|
||||
|
||||
return jarChecksum != null && jarChecksum.equals(checkContents);
|
||||
|
@ -961,7 +960,6 @@ class ProjectJava extends Project<ProjectJava> {
|
|||
* Saves the checksums for a given path - PER PROJECT (otherwise updating a jar in one place, and saving it's checksum, will verify
|
||||
* it everywhere else)
|
||||
*/
|
||||
@Override
|
||||
void saveChecksums() throws IOException {
|
||||
// by default, we save the build. When building a 'test' build, we opt to NOT save the build hashes, so that a 'normal' build
|
||||
// will then compile.
|
||||
|
@ -969,21 +967,21 @@ class ProjectJava extends Project<ProjectJava> {
|
|||
return;
|
||||
}
|
||||
|
||||
super.saveChecksums();
|
||||
hash.saveChecksums();
|
||||
|
||||
// when we verify checksums, we verify the ORIGINAL (if there is version info) -- and when we SAVE checksums, we save the NEW version
|
||||
final File currentOutputFile = this.outputFile.get();
|
||||
|
||||
// hash/save the jar file (if there was one)
|
||||
if (currentOutputFile.exists()) {
|
||||
String fileChecksum = generateChecksum(currentOutputFile);
|
||||
String fileChecksum = hash.generateChecksum(currentOutputFile);
|
||||
Builder.settings.save(this.name + ":" + currentOutputFile.getAbsolutePath(), fileChecksum);
|
||||
|
||||
if (this.jarable != null && this.jarable.includeSourceAsSeparate) {
|
||||
final File currentOutputFileSource = this.outputFile.getSource();
|
||||
|
||||
// now check the src.zip file (if there was one).
|
||||
fileChecksum = generateChecksum(currentOutputFileSource);
|
||||
fileChecksum = hash.generateChecksum(currentOutputFileSource);
|
||||
|
||||
Builder.settings.save(this.name + ":" + currentOutputFileSource.getAbsolutePath(), fileChecksum);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,229 @@
|
|||
/*
|
||||
* Copyright 2012 dorkbox, llc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package dorkbox.build.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import com.esotericsoftware.wildcard.Paths;
|
||||
|
||||
import dorkbox.BuildOptions;
|
||||
import dorkbox.Builder;
|
||||
import dorkbox.build.Project;
|
||||
import dorkbox.util.Base64Fast;
|
||||
import dorkbox.util.IO;
|
||||
|
||||
/**
|
||||
* CHECKSUM LOGIC
|
||||
*/
|
||||
@SuppressWarnings({"Convert2Diamond", "AnonymousHasLambdaAlternative"})
|
||||
public
|
||||
class Hash {
|
||||
|
||||
private static final ThreadLocal<MessageDigest> digestThreadLocal = new ThreadLocal<MessageDigest>() {
|
||||
@Override
|
||||
protected
|
||||
MessageDigest initialValue() {
|
||||
try {
|
||||
return MessageDigest.getInstance("SHA-1");
|
||||
} catch (NoSuchAlgorithmException ignored) {
|
||||
// will never happen, since SHA1 is part of java.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// set by Project.java
|
||||
public static boolean forceRebuildAll = false;
|
||||
|
||||
private transient Paths checksumPaths = new Paths();
|
||||
private final String projectName;
|
||||
private BuildOptions buildOptions;
|
||||
|
||||
public
|
||||
Hash(final String projectName, BuildOptions buildOptions) {
|
||||
this.projectName = projectName;
|
||||
this.buildOptions = buildOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add paths to be checksum'd.
|
||||
*/
|
||||
public
|
||||
void add(final Paths paths) {
|
||||
this.checksumPaths.add(paths);
|
||||
}
|
||||
|
||||
public
|
||||
void add(final String file) {
|
||||
this.checksumPaths.addFile(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the checksums for path match the saved checksums and the jar file exists, false if the check failed and the
|
||||
* project needs to rebuild
|
||||
*/
|
||||
public
|
||||
boolean verifyChecksums() throws IOException {
|
||||
if (forceRebuildAll || this.buildOptions.compiler.forceRebuild) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// check to see if our SOURCES *and check-summed files* have changed.
|
||||
String hashedContents = generateChecksums(this.checksumPaths);
|
||||
String checkContents = Builder.settings.get(this.projectName, String.class);
|
||||
|
||||
return hashedContents != null && hashedContents.equals(checkContents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the checksums for a given path
|
||||
*/
|
||||
public
|
||||
void saveChecksums() throws IOException {
|
||||
// hash/save the sources *and check-summed files* files
|
||||
String hashedContents = generateChecksums(this.checksumPaths);
|
||||
Builder.settings.save(this.projectName, hashedContents);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generates checksums for the given path
|
||||
*/
|
||||
public static
|
||||
String generateChecksum(File file) throws IOException {
|
||||
synchronized (Project.class) {
|
||||
// calculate the hash of file
|
||||
boolean found = false;
|
||||
if (file.isFile() && file.canRead()) {
|
||||
found = true;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
return null;
|
||||
}
|
||||
|
||||
MessageDigest sha1 = digestThreadLocal.get();
|
||||
sha1.reset();
|
||||
|
||||
FileInputStream inputStream = null;
|
||||
try {
|
||||
inputStream = new FileInputStream(file);
|
||||
FileChannel channel = inputStream.getChannel();
|
||||
|
||||
long length = file.length();
|
||||
if (length > Integer.MAX_VALUE) {
|
||||
// you could make this work with some care,
|
||||
// but this code does not bother.
|
||||
throw new IOException("File " + file.getAbsolutePath() + " is too large.");
|
||||
}
|
||||
|
||||
ByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, length);
|
||||
|
||||
int bufsize = 1024 * 8;
|
||||
byte[] temp = new byte[bufsize];
|
||||
int bytesRead = 0;
|
||||
|
||||
while (bytesRead < length) {
|
||||
int numBytes = (int) length - bytesRead >= bufsize ? bufsize : (int) length - bytesRead;
|
||||
buffer.get(temp, 0, numBytes);
|
||||
sha1.update(temp, 0, numBytes);
|
||||
bytesRead += numBytes;
|
||||
}
|
||||
|
||||
byte[] hashBytes = sha1.digest();
|
||||
return Base64Fast.encodeToString(hashBytes, false);
|
||||
} finally {
|
||||
IO.closeQuietly(inputStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates checksums for the given path
|
||||
*/
|
||||
public static
|
||||
String generateChecksums(Paths... paths) throws IOException {
|
||||
synchronized (Project.class) {
|
||||
// calculate the hash of all the files in the source path
|
||||
Set<String> names = new HashSet<String>(64);
|
||||
|
||||
for (Paths path : paths) {
|
||||
names.addAll(path.getPaths());
|
||||
}
|
||||
|
||||
// hash of all files. faster than using java to hash files
|
||||
MessageDigest sha1 = digestThreadLocal.get();
|
||||
sha1.reset();
|
||||
|
||||
int bufsize = 1024 * 8;
|
||||
byte[] temp = new byte[bufsize];
|
||||
int bytesRead = 0;
|
||||
|
||||
boolean found = false;
|
||||
for (String name : names) {
|
||||
File file = new File(name);
|
||||
if (file.isFile() && file.canRead()) {
|
||||
found = true;
|
||||
|
||||
FileInputStream inputStream = null;
|
||||
try {
|
||||
inputStream = new FileInputStream(file);
|
||||
FileChannel channel = inputStream.getChannel();
|
||||
|
||||
long length = file.length();
|
||||
if (length > Integer.MAX_VALUE) {
|
||||
// you could make this work with some care,
|
||||
// but this code does not bother.
|
||||
throw new IOException("File " + file.getAbsolutePath() + " is too large.");
|
||||
}
|
||||
|
||||
ByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, length);
|
||||
|
||||
while (bytesRead < length) {
|
||||
int numBytes = (int) length - bytesRead >= bufsize ? bufsize : (int) length - bytesRead;
|
||||
buffer.get(temp, 0, numBytes);
|
||||
sha1.update(temp, 0, numBytes);
|
||||
bytesRead += numBytes;
|
||||
}
|
||||
} finally {
|
||||
IO.closeQuietly(inputStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] hashBytes = sha1.digest();
|
||||
return Base64Fast.encodeToString(hashBytes, false);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,12 +15,12 @@
|
|||
*/
|
||||
package dorkbox.build.util;
|
||||
|
||||
import com.esotericsoftware.wildcard.Paths;
|
||||
import dorkbox.Builder;
|
||||
import dorkbox.build.Project;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.esotericsoftware.wildcard.Paths;
|
||||
|
||||
import dorkbox.Builder;
|
||||
|
||||
public
|
||||
class ShutdownHook implements Runnable {
|
||||
private final Paths paths;
|
||||
|
@ -36,7 +36,7 @@ class ShutdownHook implements Runnable {
|
|||
try {
|
||||
BuildLog.start();
|
||||
BuildLog.println("Saving build file checksums.");
|
||||
String hashedContents = Project.generateChecksums(paths);
|
||||
String hashedContents = Hash.generateChecksums(paths);
|
||||
Builder.settings.save("BUILD", hashedContents);
|
||||
BuildLog.finish();
|
||||
} catch (IOException e) {
|
||||
|
|
Loading…
Reference in New Issue