com.jogamp.common.util.SHASum Maven / Gradle / Ivy
Show all versions of gluegen-rt Show documentation
/**
* Copyright 2019 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of JogAmp Community.
*/
package com.jogamp.common.util;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.regex.Pattern;
import com.jogamp.common.util.cache.TempFileCache;
import com.jogamp.common.util.cache.TempJarCache;
import jogamp.common.Debug;
/**
* Utility class to produce secure hash (SHA) sums over diverse input sources.
*
* See {@link #updateDigest(MessageDigest, List)}
*
*
* This implementation is being utilized at JogAmp build time to produce various
* SHA sums over sources, class files and native libraries to ensure their identity.
* See {@link JogampVersion#getImplementationSHASources()},
* {@link JogampVersion#getImplementationSHAClasses()}
* and {@link JogampVersion#getImplementationSHANatives()}.
*
*
* {@link JogampVersion#getImplementationSHASources()} for module gluegen is produced via:
*
* java -cp build/gluegen-rt.jar com.jogamp.common.util.SHASum --algorithm 256 --exclude ".*\\.log" --exclude "make/lib/toolchain" src jcpp/src make
*
*
* @see #SHASum(MessageDigest, List, List, List)
* @see #compute(boolean)
* @see TempJarSHASum
* @see #main(String[])
*/
public class SHASum {
private static final boolean DEBUG = Debug.debug("SHASum");
/**
* {@link MessageDigest#update(byte[], int, int) Updates} the given {@code digest}
* with the bytes contained by the files denoted by the given {@code filenames} in the given order.
*
* To retrieve the list of all files traversing through directories, one may use {@link IOUtil#filesOf(List, List, List)}.
*
*
* The SHA implementation is sensitive to the order of input bytes and hence the given filename order.
*
*
* It is advised to pass given list of filenames in lexicographically sorted order to ensure reproducible outcome across all platforms,
* one may use {@link #sort(ArrayList)}.
*
*
* As an example, one could write
*
* final MessageDigest digest = ...;
* final long totalBytes = updateDigest(digest, sort(IOUtil.filesOf(Arrays.asList("sources"), null, null)));
*
*
* @param digest to be updated digest
* @param filenames list of filenames denoting files, which bytes will be used to update the digest
* @return total number of bytes read.
* @throws FileNotFoundException see {@link FileInputStream#FileInputStream(String)}
* @throws IOException see {@link InputStream#read(byte[])}
*/
public static long updateDigest(final MessageDigest digest, final List filenames) throws IOException {
long numBytes = 0;
final byte buffer[] = new byte[4096]; // avoid Platform.getMachineDataInfo().pageSizeInBytes() due to native dependency
for(int i=0; i sort(final ArrayList source) {
final String s[] = source.toArray(new String[source.size()]);
Arrays.sort(s, 0, s.length, null);
return Arrays.asList(s);
}
final MessageDigest digest;
final List origins;
final List excludes, includes;
/**
* Instance to ensure proper {@link #compute(boolean)} of identical SHA sums over same contents within given paths across machines.
*
* Instantiation of this class is lightweight, {@link #compute(boolean)} performs all operations.
*
*
* @param digest the SHA algorithm
* @param origins the mandatory path origins to be used for {@link IOUtil#filesOf(List, List, List)}
* @param excludes the optional exclude patterns to be used for {@link IOUtil#filesOf(List, List, List)}
* @param includes the optional include patterns to be used for {@link IOUtil#filesOf(List, List, List)}
* @throws IllegalArgumentException
* @throws IOException
* @throws URISyntaxException
*/
public SHASum(final MessageDigest digest, final List origins, final List excludes, final List includes) {
this.digest = digest;
this.origins = origins;
this.excludes = excludes;
this.includes = includes;
}
/**
* Implementation gathers all files traversing through given paths via {@link IOUtil#filesOf(List, List, List)},
* sorts the resulting file list via {@link #sort(ArrayList)} and finally
* calculates the SHA sum over its byte content via {@link #updateDigest(MessageDigest, List)}.
*
* This ensures identical SHA sums over same contents within given paths across machines.
*
*
* This method is heavyweight and performs all operations.
*
*
* @param verbose if true, all used files will be dumped as well as the digest result
* @return the resulting SHA value
* @throws IOException
*/
public final byte[] compute(final boolean verbose) throws IOException {
final List fnamesS = SHASum.sort(IOUtil.filesOf(origins, excludes, includes));
if( verbose ) {
for(int i=0; i getOrigins() { return origins; }
public final List getExcludes() { return excludes; }
public final List getIncludes() { return includes; }
/**
* {@link SHASum} specialization utilizing {@link TempJarCache} to access jar file content for SHA computation
*/
public static class TempJarSHASum extends SHASum {
/**
* Instance to ensure proper {@link #compute(boolean)} of identical SHA sums over same contents within given paths across machines.
*
* Instantiation of this class is lightweight, {@link #compute(boolean)} performs all operations.
*
*
* {@link TempJarCache#getTempFileCache()}'s {@link TempFileCache#getTempDir()} is used as origin for {@link IOUtil#filesOf(List, List, List)}
*
*
* @param digest the SHA algorithm
* @param jarclazz a class from the desired classpath jar file used for {@link TempJarCache#addAll(Class, com.jogamp.common.net.Uri)}
* @param excludes the optional exclude patterns to be used for {@link IOUtil#filesOf(List, List, List)}
* @param includes the optional include patterns to be used for {@link IOUtil#filesOf(List, List, List)}
* @throws SecurityException
* @throws IllegalArgumentException
* @throws IOException
* @throws URISyntaxException
*/
public TempJarSHASum(final MessageDigest digest, final Class> jarclazz, final List excludes, final List includes)
throws SecurityException, IllegalArgumentException, IOException, URISyntaxException
{
super(digest, Arrays.asList(IOUtil.slashify(TempJarCache.getTempFileCache().getTempDir().getAbsolutePath(), false, false)),
excludes, includes);
TempJarCache.addAll(jarclazz, JarUtil.getJarFileUri(jarclazz.getName(), jarclazz.getClassLoader()));
}
public final String getOrigin() { return origins.get(0); }
}
/**
* Main entry point taking var-arg path or gnu-arguments with a leading '--'.
*
* Implementation gathers all files traversing through given paths via {@link IOUtil#filesOf(List, List, List)},
* sorts the resulting file list via {@link #sort(ArrayList)} and finally
* calculates the SHA sum over its byte content via {@link #updateDigest(MessageDigest, List)}.
* This ensures identical SHA sums over same contents within given paths.
*
*
* Example to calculate the SHA-256 over our source files as performed for {@link JogampVersion#getImplementationSHASources()}
*
* java -cp build/gluegen-rt.jar com.jogamp.common.util.SHASum --algorithm 256 --exclude ".*\\.log" --exclude "make/lib/toolchain" src jcpp/src make
*
*
*
* To validate the implementation, one can gather the sorted list of files (to ensure same order)
*
* java -cp build/gluegen-rt.jar com.jogamp.common.util.SHASum --listfilesonly --exclude ".*\\.log" --exclude "make/lib/toolchain" src jcpp/src make >& java.sorted.txt
*
* and then calculate the shasum independently
*
* find `cat java.sorted.txt` -exec cat {} + | shasum -a 256 -b - | awk '{print $1}'
*
*
* @param args
* @throws IOException
* @throws URISyntaxException
* @throws IllegalArgumentException
*/
public static void main(final String[] args) throws IOException {
boolean listFilesOnly = false;
int shabits = 256;
int i;
final ArrayList pathU = new ArrayList();
final ArrayList excludes = new ArrayList();
final ArrayList includes = new ArrayList();
{
for(i=0; i -> <"+excludes.get(excludes.size()-1)+">");
}
} else if( args[i].equals("--include")) {
includes.add(Pattern.compile(args[++i]));
if( DEBUG ) {
System.err.println("adding include: <"+args[i]+"> -> <"+includes.get(includes.size()-1)+">");
}
} else if( args[i].equals("--listfilesonly")) {
listFilesOnly = true;
} else {
System.err.println("Abort, unknown argument: "+args[i]);
return;
}
} else {
pathU.add(args[i]);
if( DEBUG ) {
System.err.println("adding path: <"+args[i]+">");
}
}
}
}
if( listFilesOnly ) {
final List fnamesS = sort(IOUtil.filesOf(pathU, excludes, includes));
for(i=0; i